• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/Program.h"
17 #include "libANGLE/Semaphore.h"
18 #include "libANGLE/Surface.h"
19 #include "libANGLE/angletypes.h"
20 #include "libANGLE/renderer/renderer_utils.h"
21 #include "libANGLE/renderer/vulkan/BufferVk.h"
22 #include "libANGLE/renderer/vulkan/CompilerVk.h"
23 #include "libANGLE/renderer/vulkan/FenceNVVk.h"
24 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
25 #include "libANGLE/renderer/vulkan/MemoryObjectVk.h"
26 #include "libANGLE/renderer/vulkan/OverlayVk.h"
27 #include "libANGLE/renderer/vulkan/ProgramPipelineVk.h"
28 #include "libANGLE/renderer/vulkan/ProgramVk.h"
29 #include "libANGLE/renderer/vulkan/QueryVk.h"
30 #include "libANGLE/renderer/vulkan/RenderbufferVk.h"
31 #include "libANGLE/renderer/vulkan/RendererVk.h"
32 #include "libANGLE/renderer/vulkan/SamplerVk.h"
33 #include "libANGLE/renderer/vulkan/SemaphoreVk.h"
34 #include "libANGLE/renderer/vulkan/ShaderVk.h"
35 #include "libANGLE/renderer/vulkan/SurfaceVk.h"
36 #include "libANGLE/renderer/vulkan/SyncVk.h"
37 #include "libANGLE/renderer/vulkan/TextureVk.h"
38 #include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
39 #include "libANGLE/renderer/vulkan/VertexArrayVk.h"
40 
41 #include "libANGLE/trace.h"
42 
43 #include <iostream>
44 
45 namespace rx
46 {
47 
48 namespace
49 {
50 // The value to assign an alpha channel that's emulated.  The type is unsigned int, though it will
51 // automatically convert to the actual data type.
52 constexpr unsigned int kEmulatedAlphaValue = 1;
53 
54 // For shader uniforms such as gl_DepthRange and the viewport size.
55 struct GraphicsDriverUniforms
56 {
57     std::array<float, 4> viewport;
58 
59     float halfRenderAreaHeight;
60     float viewportYScale;
61     float negViewportYScale;
62     uint32_t xfbActiveUnpaused;
63     uint32_t xfbVerticesPerDraw;
64     // NOTE: Explicit padding. Fill in with useful data when needed in the future.
65     std::array<int32_t, 3> padding;
66 
67     std::array<int32_t, 4> xfbBufferOffsets;
68 
69     // .xy contain packed 8-bit values for atomic counter buffer offsets.  These offsets are
70     // within Vulkan's minStorageBufferOffsetAlignment limit and are used to support unaligned
71     // offsets allowed in GL.
72     //
73     // .zw are unused.
74     std::array<uint32_t, 4> acbBufferOffsets;
75 
76     // We'll use x, y, z for near / far / diff respectively.
77     std::array<float, 4> depthRange;
78 
79     // Used to pre-rotate gl_Position for swapchain images on Android (a mat2, which is padded to
80     // the size of two vec4's).
81     std::array<float, 8> preRotation;
82 };
83 
84 struct ComputeDriverUniforms
85 {
86     // Atomic counter buffer offsets with the same layout as in GraphicsDriverUniforms.
87     std::array<uint32_t, 4> acbBufferOffsets;
88 };
89 
DefaultGLErrorCode(VkResult result)90 GLenum DefaultGLErrorCode(VkResult result)
91 {
92     switch (result)
93     {
94         case VK_ERROR_OUT_OF_HOST_MEMORY:
95         case VK_ERROR_OUT_OF_DEVICE_MEMORY:
96         case VK_ERROR_TOO_MANY_OBJECTS:
97             return GL_OUT_OF_MEMORY;
98         default:
99             return GL_INVALID_OPERATION;
100     }
101 }
102 
103 constexpr gl::ShaderMap<vk::ImageLayout> kShaderReadOnlyImageLayouts = {
104     {gl::ShaderType::Vertex, vk::ImageLayout::VertexShaderReadOnly},
105     {gl::ShaderType::Fragment, vk::ImageLayout::FragmentShaderReadOnly},
106     {gl::ShaderType::Geometry, vk::ImageLayout::GeometryShaderReadOnly},
107     {gl::ShaderType::Compute, vk::ImageLayout::ComputeShaderReadOnly}};
108 
109 constexpr gl::ShaderMap<vk::ImageLayout> kShaderWriteImageLayouts = {
110     {gl::ShaderType::Vertex, vk::ImageLayout::VertexShaderWrite},
111     {gl::ShaderType::Fragment, vk::ImageLayout::FragmentShaderWrite},
112     {gl::ShaderType::Geometry, vk::ImageLayout::GeometryShaderWrite},
113     {gl::ShaderType::Compute, vk::ImageLayout::ComputeShaderWrite}};
114 
115 constexpr VkColorComponentFlags kAllColorChannelsMask =
116     (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
117      VK_COLOR_COMPONENT_A_BIT);
118 
119 constexpr VkBufferUsageFlags kVertexBufferUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
120 constexpr size_t kDefaultValueSize              = sizeof(gl::VertexAttribCurrentValueData::Values);
121 constexpr size_t kDefaultBufferSize             = kDefaultValueSize * 16;
122 constexpr size_t kDefaultPoolAllocatorPageSize  = 16 * 1024;
123 constexpr size_t kDriverUniformsAllocatorPageSize = 4 * 1024;
124 
125 constexpr size_t kInFlightCommandsLimit = 100u;
126 
127 // Dumping the command stream is disabled by default.
128 constexpr bool kEnableCommandStreamDiagnostics = false;
129 
InitializeSubmitInfo(VkSubmitInfo * submitInfo,const vk::PrimaryCommandBuffer & commandBuffer,const std::vector<VkSemaphore> & waitSemaphores,std::vector<VkPipelineStageFlags> * waitSemaphoreStageMasks,const vk::Semaphore * signalSemaphore)130 void InitializeSubmitInfo(VkSubmitInfo *submitInfo,
131                           const vk::PrimaryCommandBuffer &commandBuffer,
132                           const std::vector<VkSemaphore> &waitSemaphores,
133                           std::vector<VkPipelineStageFlags> *waitSemaphoreStageMasks,
134                           const vk::Semaphore *signalSemaphore)
135 {
136     // Verify that the submitInfo has been zero'd out.
137     ASSERT(submitInfo->signalSemaphoreCount == 0);
138 
139     submitInfo->sType              = VK_STRUCTURE_TYPE_SUBMIT_INFO;
140     submitInfo->commandBufferCount = commandBuffer.valid() ? 1 : 0;
141     submitInfo->pCommandBuffers    = commandBuffer.ptr();
142 
143     if (waitSemaphoreStageMasks->size() < waitSemaphores.size())
144     {
145         waitSemaphoreStageMasks->resize(waitSemaphores.size(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
146     }
147 
148     submitInfo->waitSemaphoreCount = static_cast<uint32_t>(waitSemaphores.size());
149     submitInfo->pWaitSemaphores    = waitSemaphores.data();
150     submitInfo->pWaitDstStageMask  = waitSemaphoreStageMasks->data();
151 
152     if (signalSemaphore)
153     {
154         submitInfo->signalSemaphoreCount = 1;
155         submitInfo->pSignalSemaphores    = signalSemaphore->ptr();
156     }
157 }
158 
GetCoverageSampleCount(const gl::State & glState,FramebufferVk * drawFramebuffer)159 uint32_t GetCoverageSampleCount(const gl::State &glState, FramebufferVk *drawFramebuffer)
160 {
161     if (!glState.isSampleCoverageEnabled())
162     {
163         return 0;
164     }
165 
166     // Get a fraction of the samples based on the coverage parameters.
167     return static_cast<uint32_t>(
168         std::round(glState.getSampleCoverageValue() * drawFramebuffer->getSamples()));
169 }
170 
ApplySampleCoverage(const gl::State & glState,uint32_t coverageSampleCount,uint32_t maskNumber,uint32_t * maskOut)171 void ApplySampleCoverage(const gl::State &glState,
172                          uint32_t coverageSampleCount,
173                          uint32_t maskNumber,
174                          uint32_t *maskOut)
175 {
176     if (!glState.isSampleCoverageEnabled())
177     {
178         return;
179     }
180 
181     uint32_t maskBitOffset = maskNumber * 32;
182     uint32_t coverageMask  = coverageSampleCount >= (maskBitOffset + 32)
183                                 ? std::numeric_limits<uint32_t>::max()
184                                 : (1u << (coverageSampleCount - maskBitOffset)) - 1;
185 
186     if (glState.getSampleCoverageInvert())
187     {
188         coverageMask = ~coverageMask;
189     }
190 
191     *maskOut &= coverageMask;
192 }
193 
GetLoadOpShorthand(uint32_t loadOp)194 char GetLoadOpShorthand(uint32_t loadOp)
195 {
196     switch (loadOp)
197     {
198         case VK_ATTACHMENT_LOAD_OP_CLEAR:
199             return 'C';
200         case VK_ATTACHMENT_LOAD_OP_LOAD:
201             return 'L';
202         default:
203             return 'D';
204     }
205 }
206 
GetStoreOpShorthand(uint32_t storeOp)207 char GetStoreOpShorthand(uint32_t storeOp)
208 {
209     switch (storeOp)
210     {
211         case VK_ATTACHMENT_STORE_OP_STORE:
212             return 'S';
213         default:
214             return 'D';
215     }
216 }
217 
218 // When an Android surface is rotated differently than the device's native orientation, ANGLE must
219 // rotate gl_Position in the vertex shader.  The following are the rotation matrices used.
220 //
221 // Note: these are mat2's that are appropriately padded (4 floats per row).
222 using PreRotationMatrixValues = std::array<float, 8>;
223 constexpr angle::PackedEnumMap<rx::SurfaceRotationType,
224                                PreRotationMatrixValues,
225                                angle::EnumSize<rx::SurfaceRotationType>()>
226     kPreRotationMatrices = {
227         {{rx::SurfaceRotationType::Identity, {{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
228          {rx::SurfaceRotationType::Rotated90Degrees,
229           {{0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}},
230          {rx::SurfaceRotationType::Rotated180Degrees,
231           {{-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}}},
232          {rx::SurfaceRotationType::Rotated270Degrees,
233           {{0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f}}},
234          {rx::SurfaceRotationType::FlippedIdentity,
235           {{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f}}},
236          {rx::SurfaceRotationType::FlippedRotated90Degrees,
237           {{0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f}}},
238          {rx::SurfaceRotationType::FlippedRotated180Degrees,
239           {{-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
240          {rx::SurfaceRotationType::FlippedRotated270Degrees,
241           {{0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}}}};
242 
IsRotatedAspectRatio(SurfaceRotationType rotation)243 bool IsRotatedAspectRatio(SurfaceRotationType rotation)
244 {
245     return ((rotation == SurfaceRotationType::Rotated90Degrees) ||
246             (rotation == SurfaceRotationType::Rotated270Degrees) ||
247             (rotation == SurfaceRotationType::FlippedRotated90Degrees) ||
248             (rotation == SurfaceRotationType::FlippedRotated270Degrees));
249 }
250 
DetermineSurfaceRotation(gl::Framebuffer * framebuffer,WindowSurfaceVk * windowSurface)251 SurfaceRotationType DetermineSurfaceRotation(gl::Framebuffer *framebuffer,
252                                              WindowSurfaceVk *windowSurface)
253 {
254     if (windowSurface && framebuffer->isDefault())
255     {
256         switch (windowSurface->getPreTransform())
257         {
258             case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
259                 // Do not rotate gl_Position (surface matches the device's orientation):
260                 return SurfaceRotationType::Identity;
261             case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
262                 // Rotate gl_Position 90 degrees:
263                 return SurfaceRotationType::Rotated90Degrees;
264             case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
265                 // Rotate gl_Position 180 degrees:
266                 return SurfaceRotationType::Rotated180Degrees;
267             case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
268                 // Rotate gl_Position 270 degrees:
269                 return SurfaceRotationType::Rotated180Degrees;
270             default:
271                 UNREACHABLE();
272                 return SurfaceRotationType::Identity;
273         }
274     }
275     else
276     {
277         // Do not rotate gl_Position (offscreen framebuffer):
278         return SurfaceRotationType::Identity;
279     }
280 }
281 
282 // Should not generate a copy with modern C++.
GetTraceEventName(const char * title,uint32_t counter)283 EventName GetTraceEventName(const char *title, uint32_t counter)
284 {
285     EventName buf;
286     snprintf(buf.data(), kMaxGpuEventNameLen - 1, "%s %u", title, counter);
287     return buf;
288 }
289 }  // anonymous namespace
290 
DriverUniformsDescriptorSet()291 ContextVk::DriverUniformsDescriptorSet::DriverUniformsDescriptorSet()
292     : descriptorSet(VK_NULL_HANDLE), dynamicOffset(0)
293 {}
294 
295 ContextVk::DriverUniformsDescriptorSet::~DriverUniformsDescriptorSet() = default;
296 
init(RendererVk * rendererVk)297 void ContextVk::DriverUniformsDescriptorSet::init(RendererVk *rendererVk)
298 {
299     size_t minAlignment = static_cast<size_t>(
300         rendererVk->getPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment);
301     dynamicBuffer.init(rendererVk, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, minAlignment,
302                        kDriverUniformsAllocatorPageSize, true);
303 }
304 
destroy(RendererVk * renderer)305 void ContextVk::DriverUniformsDescriptorSet::destroy(RendererVk *renderer)
306 {
307     descriptorSetLayout.reset();
308     descriptorPoolBinding.reset();
309     dynamicBuffer.destroy(renderer);
310 }
311 
312 // CommandBatch implementation.
313 CommandBatch::CommandBatch() = default;
314 
315 CommandBatch::~CommandBatch() = default;
316 
CommandBatch(CommandBatch && other)317 CommandBatch::CommandBatch(CommandBatch &&other)
318 {
319     *this = std::move(other);
320 }
321 
operator =(CommandBatch && other)322 CommandBatch &CommandBatch::operator=(CommandBatch &&other)
323 {
324     std::swap(primaryCommands, other.primaryCommands);
325     std::swap(commandPool, other.commandPool);
326     std::swap(fence, other.fence);
327     std::swap(serial, other.serial);
328     return *this;
329 }
330 
destroy(VkDevice device)331 void CommandBatch::destroy(VkDevice device)
332 {
333     primaryCommands.destroy(device);
334     commandPool.destroy(device);
335     fence.reset(device);
336 }
337 
338 // CommandQueue implementation.
339 CommandQueue::CommandQueue()  = default;
340 CommandQueue::~CommandQueue() = default;
341 
destroy(VkDevice device)342 void CommandQueue::destroy(VkDevice device)
343 {
344     mPrimaryCommandPool.destroy(device);
345     ASSERT(mInFlightCommands.empty() && mGarbageQueue.empty());
346 }
347 
init(vk::Context * context)348 angle::Result CommandQueue::init(vk::Context *context)
349 {
350     RendererVk *renderer = context->getRenderer();
351 
352     // Initialize the command pool now that we know the queue family index.
353     uint32_t queueFamilyIndex = renderer->getQueueFamilyIndex();
354     ANGLE_TRY(mPrimaryCommandPool.init(context, queueFamilyIndex));
355 
356     return angle::Result::Continue;
357 }
358 
checkCompletedCommands(vk::Context * context)359 angle::Result CommandQueue::checkCompletedCommands(vk::Context *context)
360 {
361     RendererVk *renderer = context->getRenderer();
362     VkDevice device      = renderer->getDevice();
363 
364     int finishedCount = 0;
365 
366     for (CommandBatch &batch : mInFlightCommands)
367     {
368         VkResult result = batch.fence.get().getStatus(device);
369         if (result == VK_NOT_READY)
370         {
371             break;
372         }
373         ANGLE_VK_TRY(context, result);
374 
375         renderer->onCompletedSerial(batch.serial);
376 
377         renderer->resetSharedFence(&batch.fence);
378         ANGLE_TRACE_EVENT0("gpu.angle", "command buffer recycling");
379         batch.commandPool.destroy(device);
380         ANGLE_TRY(releasePrimaryCommandBuffer(context, std::move(batch.primaryCommands)));
381         ++finishedCount;
382     }
383 
384     if (finishedCount > 0)
385     {
386         auto beginIter = mInFlightCommands.begin();
387         mInFlightCommands.erase(beginIter, beginIter + finishedCount);
388     }
389 
390     Serial lastCompleted = renderer->getLastCompletedQueueSerial();
391 
392     size_t freeIndex = 0;
393     for (; freeIndex < mGarbageQueue.size(); ++freeIndex)
394     {
395         vk::GarbageAndSerial &garbageList = mGarbageQueue[freeIndex];
396         if (garbageList.getSerial() < lastCompleted)
397         {
398             for (vk::GarbageObject &garbage : garbageList.get())
399             {
400                 garbage.destroy(renderer);
401             }
402         }
403         else
404         {
405             break;
406         }
407     }
408 
409     // Remove the entries from the garbage list - they should be ready to go.
410     if (freeIndex > 0)
411     {
412         mGarbageQueue.erase(mGarbageQueue.begin(), mGarbageQueue.begin() + freeIndex);
413     }
414 
415     return angle::Result::Continue;
416 }
417 
releaseToCommandBatch(vk::Context * context,vk::PrimaryCommandBuffer && commandBuffer,vk::CommandPool * commandPool,CommandBatch * batch)418 angle::Result CommandQueue::releaseToCommandBatch(vk::Context *context,
419                                                   vk::PrimaryCommandBuffer &&commandBuffer,
420                                                   vk::CommandPool *commandPool,
421                                                   CommandBatch *batch)
422 {
423     RendererVk *renderer = context->getRenderer();
424     VkDevice device      = renderer->getDevice();
425 
426     batch->primaryCommands = std::move(commandBuffer);
427 
428     if (commandPool->valid())
429     {
430         batch->commandPool = std::move(*commandPool);
431         // Recreate CommandPool
432         VkCommandPoolCreateInfo poolInfo = {};
433         poolInfo.sType                   = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
434         poolInfo.flags                   = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
435         poolInfo.queueFamilyIndex        = renderer->getQueueFamilyIndex();
436 
437         ANGLE_VK_TRY(context, commandPool->init(device, poolInfo));
438     }
439 
440     return angle::Result::Continue;
441 }
442 
clearAllGarbage(RendererVk * renderer)443 void CommandQueue::clearAllGarbage(RendererVk *renderer)
444 {
445     for (vk::GarbageAndSerial &garbageList : mGarbageQueue)
446     {
447         for (vk::GarbageObject &garbage : garbageList.get())
448         {
449             garbage.destroy(renderer);
450         }
451     }
452     mGarbageQueue.clear();
453 }
454 
allocatePrimaryCommandBuffer(vk::Context * context,const vk::CommandPool & commandPool,vk::PrimaryCommandBuffer * commandBufferOut)455 angle::Result CommandQueue::allocatePrimaryCommandBuffer(vk::Context *context,
456                                                          const vk::CommandPool &commandPool,
457                                                          vk::PrimaryCommandBuffer *commandBufferOut)
458 {
459     return mPrimaryCommandPool.allocate(context, commandBufferOut);
460 }
461 
releasePrimaryCommandBuffer(vk::Context * context,vk::PrimaryCommandBuffer && commandBuffer)462 angle::Result CommandQueue::releasePrimaryCommandBuffer(vk::Context *context,
463                                                         vk::PrimaryCommandBuffer &&commandBuffer)
464 {
465     ASSERT(mPrimaryCommandPool.valid());
466     ANGLE_TRY(mPrimaryCommandPool.collect(context, std::move(commandBuffer)));
467 
468     return angle::Result::Continue;
469 }
470 
handleDeviceLost(RendererVk * renderer)471 void CommandQueue::handleDeviceLost(RendererVk *renderer)
472 {
473     VkDevice device = renderer->getDevice();
474 
475     for (CommandBatch &batch : mInFlightCommands)
476     {
477         // On device loss we need to wait for fence to be signaled before destroying it
478         VkResult status = batch.fence.get().wait(device, renderer->getMaxFenceWaitTimeNs());
479         // If the wait times out, it is probably not possible to recover from lost device
480         ASSERT(status == VK_SUCCESS || status == VK_ERROR_DEVICE_LOST);
481 
482         // On device lost, here simply destroy the CommandBuffer, it will fully cleared later
483         // by CommandPool::destroy
484         batch.primaryCommands.destroy(device);
485 
486         batch.commandPool.destroy(device);
487         batch.fence.reset(device);
488     }
489     mInFlightCommands.clear();
490 }
491 
hasInFlightCommands() const492 bool CommandQueue::hasInFlightCommands() const
493 {
494     return !mInFlightCommands.empty();
495 }
496 
finishToSerial(vk::Context * context,Serial serial,uint64_t timeout)497 angle::Result CommandQueue::finishToSerial(vk::Context *context, Serial serial, uint64_t timeout)
498 {
499     if (mInFlightCommands.empty())
500     {
501         return angle::Result::Continue;
502     }
503 
504     // Find the first batch with serial equal to or bigger than given serial (note that
505     // the batch serials are unique, otherwise upper-bound would have been necessary).
506     //
507     // Note: we don't check for the exact serial, because it may belong to another context.  For
508     // example, imagine the following submissions:
509     //
510     // - Context 1: Serial 1, Serial 3, Serial 5
511     // - Context 2: Serial 2, Serial 4, Serial 6
512     //
513     // And imagine none of the submissions have finished yet.  Now if Context 2 asks for
514     // finishToSerial(3), it will have no choice but to finish until Serial 4 instead.
515     size_t batchIndex = mInFlightCommands.size() - 1;
516     for (size_t i = 0; i < mInFlightCommands.size(); ++i)
517     {
518         if (mInFlightCommands[i].serial >= serial)
519         {
520             batchIndex = i;
521             break;
522         }
523     }
524     const CommandBatch &batch = mInFlightCommands[batchIndex];
525 
526     // Wait for it finish
527     VkDevice device = context->getDevice();
528     VkResult status = batch.fence.get().wait(device, timeout);
529 
530     ANGLE_VK_TRY(context, status);
531 
532     // Clean up finished batches.
533     return checkCompletedCommands(context);
534 }
535 
submitFrame(vk::Context * context,egl::ContextPriority priority,const VkSubmitInfo & submitInfo,const vk::Shared<vk::Fence> & sharedFence,vk::GarbageList * currentGarbage,vk::CommandPool * commandPool,vk::PrimaryCommandBuffer && commandBuffer)536 angle::Result CommandQueue::submitFrame(vk::Context *context,
537                                         egl::ContextPriority priority,
538                                         const VkSubmitInfo &submitInfo,
539                                         const vk::Shared<vk::Fence> &sharedFence,
540                                         vk::GarbageList *currentGarbage,
541                                         vk::CommandPool *commandPool,
542                                         vk::PrimaryCommandBuffer &&commandBuffer)
543 {
544     ANGLE_TRACE_EVENT0("gpu.angle", "CommandQueue::submitFrame");
545     VkFenceCreateInfo fenceInfo = {};
546     fenceInfo.sType             = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
547     fenceInfo.flags             = 0;
548 
549     RendererVk *renderer = context->getRenderer();
550     VkDevice device      = renderer->getDevice();
551 
552     vk::DeviceScoped<CommandBatch> scopedBatch(device);
553     CommandBatch &batch = scopedBatch.get();
554     batch.fence.copy(device, sharedFence);
555 
556     ANGLE_TRY(
557         renderer->queueSubmit(context, priority, submitInfo, &batch.fence.get(), &batch.serial));
558 
559     if (!currentGarbage->empty())
560     {
561         mGarbageQueue.emplace_back(std::move(*currentGarbage), batch.serial);
562     }
563 
564     // Store the primary CommandBuffer and command pool used for secondary CommandBuffers
565     // in the in-flight list.
566     ANGLE_TRY(releaseToCommandBatch(context, std::move(commandBuffer), commandPool, &batch));
567 
568     mInFlightCommands.emplace_back(scopedBatch.release());
569 
570     ANGLE_TRY(checkCompletedCommands(context));
571 
572     // CPU should be throttled to avoid mInFlightCommands from growing too fast. Important for
573     // off-screen scenarios.
574     while (mInFlightCommands.size() > kInFlightCommandsLimit)
575     {
576         ANGLE_TRY(finishToSerial(context, mInFlightCommands[0].serial,
577                                  renderer->getMaxFenceWaitTimeNs()));
578     }
579 
580     return angle::Result::Continue;
581 }
582 
getLastSubmittedFence(const vk::Context * context) const583 vk::Shared<vk::Fence> CommandQueue::getLastSubmittedFence(const vk::Context *context) const
584 {
585     vk::Shared<vk::Fence> fence;
586     if (!mInFlightCommands.empty())
587     {
588         fence.copy(context->getDevice(), mInFlightCommands.back().fence);
589     }
590 
591     return fence;
592 }
593 
GetContextPriority(const gl::State & state)594 egl::ContextPriority GetContextPriority(const gl::State &state)
595 {
596     return egl::FromEGLenum<egl::ContextPriority>(state.getContextPriority());
597 }
598 
599 // ContextVk implementation.
ContextVk(const gl::State & state,gl::ErrorSet * errorSet,RendererVk * renderer)600 ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk *renderer)
601     : ContextImpl(state, errorSet),
602       vk::Context(renderer),
603       mRenderPassCommandBuffer(nullptr),
604       mCurrentGraphicsPipeline(nullptr),
605       mCurrentComputePipeline(nullptr),
606       mCurrentDrawMode(gl::PrimitiveMode::InvalidEnum),
607       mCurrentWindowSurface(nullptr),
608       mCurrentRotationDrawFramebuffer(SurfaceRotationType::Identity),
609       mCurrentRotationReadFramebuffer(SurfaceRotationType::Identity),
610       mVertexArray(nullptr),
611       mDrawFramebuffer(nullptr),
612       mProgram(nullptr),
613       mExecutable(nullptr),
614       mActiveQueryAnySamples(nullptr),
615       mActiveQueryAnySamplesConservative(nullptr),
616       mLastIndexBufferOffset(0),
617       mCurrentDrawElementsType(gl::DrawElementsType::InvalidEnum),
618       mXfbBaseVertex(0),
619       mXfbVertexCountPerInstance(0),
620       mClearColorMask(kAllColorChannelsMask),
621       mFlipYForCurrentSurface(false),
622       mIsAnyHostVisibleBufferWritten(false),
623       mEmulateSeamfulCubeMapSampling(false),
624       mUseOldRewriteStructSamplers(false),
625       mPoolAllocator(kDefaultPoolAllocatorPageSize, 1),
626       mHasPrimaryCommands(false),
627       mGpuEventsEnabled(false),
628       mGpuClockSync{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()},
629       mGpuEventTimestampOrigin(0),
630       mPrimaryBufferCounter(0),
631       mRenderPassCounter(0),
632       mContextPriority(renderer->getDriverPriority(GetContextPriority(state)))
633 {
634     ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::ContextVk");
635     memset(&mClearColorValue, 0, sizeof(mClearColorValue));
636     memset(&mClearDepthStencilValue, 0, sizeof(mClearDepthStencilValue));
637 
638     mNonIndexedDirtyBitsMask.set();
639     mNonIndexedDirtyBitsMask.reset(DIRTY_BIT_INDEX_BUFFER);
640 
641     mIndexedDirtyBitsMask.set();
642 
643     mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_PIPELINE);
644     mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_TEXTURES);
645     mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
646     mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
647     mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES);
648     if (getFeatures().supportsTransformFeedbackExtension.enabled ||
649         getFeatures().emulateTransformFeedback.enabled)
650     {
651         mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
652     }
653     if (getFeatures().supportsTransformFeedbackExtension.enabled)
654     {
655         mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_STATE);
656         mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME);
657     }
658     mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
659     mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING);
660 
661     mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_PIPELINE);
662     mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_TEXTURES);
663     mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES);
664     mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
665     mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING);
666 
667     mNewGraphicsPipelineDirtyBits.set(DIRTY_BIT_PIPELINE);
668     if (getFeatures().supportsTransformFeedbackExtension.enabled)
669     {
670         mNewGraphicsPipelineDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME);
671     }
672 
673     mGraphicsDirtyBitHandlers[DIRTY_BIT_DEFAULT_ATTRIBS] =
674         &ContextVk::handleDirtyGraphicsDefaultAttribs;
675     mGraphicsDirtyBitHandlers[DIRTY_BIT_PIPELINE] = &ContextVk::handleDirtyGraphicsPipeline;
676     mGraphicsDirtyBitHandlers[DIRTY_BIT_TEXTURES] = &ContextVk::handleDirtyGraphicsTextures;
677     mGraphicsDirtyBitHandlers[DIRTY_BIT_VERTEX_BUFFERS] =
678         &ContextVk::handleDirtyGraphicsVertexBuffers;
679     mGraphicsDirtyBitHandlers[DIRTY_BIT_INDEX_BUFFER] = &ContextVk::handleDirtyGraphicsIndexBuffer;
680     mGraphicsDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] =
681         &ContextVk::handleDirtyGraphicsDriverUniforms;
682     mGraphicsDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS_BINDING] =
683         &ContextVk::handleDirtyGraphicsDriverUniformsBinding;
684     mGraphicsDirtyBitHandlers[DIRTY_BIT_SHADER_RESOURCES] =
685         &ContextVk::handleDirtyGraphicsShaderResources;
686     if (getFeatures().supportsTransformFeedbackExtension.enabled)
687     {
688         mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
689             &ContextVk::handleDirtyGraphicsTransformFeedbackBuffersExtension;
690         mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_STATE] =
691             &ContextVk::handleDirtyGraphicsTransformFeedbackState;
692         mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME] =
693             &ContextVk::handleDirtyGraphicsTransformFeedbackResume;
694     }
695     else if (getFeatures().emulateTransformFeedback.enabled)
696     {
697         mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
698             &ContextVk::handleDirtyGraphicsTransformFeedbackBuffersEmulation;
699     }
700 
701     mGraphicsDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] = &ContextVk::handleDirtyDescriptorSets;
702 
703     mComputeDirtyBitHandlers[DIRTY_BIT_PIPELINE] = &ContextVk::handleDirtyComputePipeline;
704     mComputeDirtyBitHandlers[DIRTY_BIT_TEXTURES] = &ContextVk::handleDirtyComputeTextures;
705     mComputeDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] =
706         &ContextVk::handleDirtyComputeDriverUniforms;
707     mComputeDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS_BINDING] =
708         &ContextVk::handleDirtyComputeDriverUniformsBinding;
709     mComputeDirtyBitHandlers[DIRTY_BIT_SHADER_RESOURCES] =
710         &ContextVk::handleDirtyComputeShaderResources;
711     mComputeDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] = &ContextVk::handleDirtyDescriptorSets;
712 
713     mGraphicsDirtyBits = mNewGraphicsCommandBufferDirtyBits;
714     mComputeDirtyBits  = mNewComputeCommandBufferDirtyBits;
715 
716     mActiveTextures.fill({nullptr, nullptr});
717     mActiveImages.fill(nullptr);
718 
719     mPipelineDirtyBitsMask.set();
720     mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_TEXTURE_BINDINGS);
721 }
722 
723 ContextVk::~ContextVk() = default;
724 
onDestroy(const gl::Context * context)725 void ContextVk::onDestroy(const gl::Context *context)
726 {
727     // This will not destroy any resources. It will release them to be collected after finish.
728     mIncompleteTextures.onDestroy(context);
729 
730     // Flush and complete current outstanding work before destruction.
731     (void)finishImpl();
732 
733     VkDevice device = getDevice();
734 
735     for (DriverUniformsDescriptorSet &driverUniforms : mDriverUniforms)
736     {
737         driverUniforms.destroy(mRenderer);
738     }
739 
740     mDriverUniformsDescriptorPool.destroy(device);
741 
742     for (vk::DynamicBuffer &defaultBuffer : mDefaultAttribBuffers)
743     {
744         defaultBuffer.destroy(mRenderer);
745     }
746 
747     for (vk::DynamicQueryPool &queryPool : mQueryPools)
748     {
749         queryPool.destroy(device);
750     }
751 
752     ASSERT(mCurrentGarbage.empty());
753 
754     mCommandQueue.destroy(device);
755 
756     mResourceUseList.releaseResourceUses();
757 
758     mUtils.destroy(device);
759 
760     mRenderPassCache.destroy(device);
761     mSubmitFence.reset(device);
762     mShaderLibrary.destroy(device);
763     mGpuEventQueryPool.destroy(device);
764     mCommandPool.destroy(device);
765     mPrimaryCommands.destroy(device);
766 }
767 
getIncompleteTexture(const gl::Context * context,gl::TextureType type,gl::Texture ** textureOut)768 angle::Result ContextVk::getIncompleteTexture(const gl::Context *context,
769                                               gl::TextureType type,
770                                               gl::Texture **textureOut)
771 {
772     // At some point, we'll need to support multisample and we'll pass "this" instead of nullptr
773     // and implement the necessary interface.
774     return mIncompleteTextures.getIncompleteTexture(context, type, nullptr, textureOut);
775 }
776 
initialize()777 angle::Result ContextVk::initialize()
778 {
779     ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::initialize");
780 
781     VkDescriptorPoolSize driverSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1};
782     ANGLE_TRY(mDriverUniformsDescriptorPool.init(this, &driverSetSize, 1));
783 
784     ANGLE_TRY(mQueryPools[gl::QueryType::AnySamples].init(this, VK_QUERY_TYPE_OCCLUSION,
785                                                           vk::kDefaultOcclusionQueryPoolSize));
786     ANGLE_TRY(mQueryPools[gl::QueryType::AnySamplesConservative].init(
787         this, VK_QUERY_TYPE_OCCLUSION, vk::kDefaultOcclusionQueryPoolSize));
788 
789     // Only initialize the timestamp query pools if the extension is available.
790     if (mRenderer->getQueueFamilyProperties().timestampValidBits > 0)
791     {
792         ANGLE_TRY(mQueryPools[gl::QueryType::Timestamp].init(this, VK_QUERY_TYPE_TIMESTAMP,
793                                                              vk::kDefaultTimestampQueryPoolSize));
794         ANGLE_TRY(mQueryPools[gl::QueryType::TimeElapsed].init(this, VK_QUERY_TYPE_TIMESTAMP,
795                                                                vk::kDefaultTimestampQueryPoolSize));
796     }
797 
798     // Init gles to vulkan index type map
799     initIndexTypeMap();
800 
801     // Init driver uniforms and get the descriptor set layouts.
802     constexpr angle::PackedEnumMap<PipelineType, VkShaderStageFlags> kPipelineStages = {
803         {PipelineType::Graphics, VK_SHADER_STAGE_ALL_GRAPHICS},
804         {PipelineType::Compute, VK_SHADER_STAGE_COMPUTE_BIT},
805     };
806     for (PipelineType pipeline : angle::AllEnums<PipelineType>())
807     {
808         mDriverUniforms[pipeline].init(mRenderer);
809 
810         vk::DescriptorSetLayoutDesc desc =
811             getDriverUniformsDescriptorSetDesc(kPipelineStages[pipeline]);
812         ANGLE_TRY(mRenderer->getDescriptorSetLayout(
813             this, desc, &mDriverUniforms[pipeline].descriptorSetLayout));
814     }
815 
816     mGraphicsPipelineDesc.reset(new vk::GraphicsPipelineDesc());
817     mGraphicsPipelineDesc->initDefaults();
818 
819     // Initialize current value/default attribute buffers.
820     for (vk::DynamicBuffer &buffer : mDefaultAttribBuffers)
821     {
822         buffer.init(mRenderer, kVertexBufferUsage, 1, kDefaultBufferSize, true);
823     }
824 
825     ANGLE_TRY(mCommandQueue.init(this));
826 
827 #if ANGLE_ENABLE_VULKAN_GPU_TRACE_EVENTS
828     angle::PlatformMethods *platform = ANGLEPlatformCurrent();
829     ASSERT(platform);
830 
831     // GPU tracing workaround for anglebug.com/2927.  The renderer should not emit gpu events
832     // during platform discovery.
833     const unsigned char *gpuEventsEnabled =
834         platform->getTraceCategoryEnabledFlag(platform, "gpu.angle.gpu");
835     mGpuEventsEnabled = gpuEventsEnabled && *gpuEventsEnabled;
836 #endif
837 
838     mEmulateSeamfulCubeMapSampling = shouldEmulateSeamfulCubeMapSampling();
839 
840     mUseOldRewriteStructSamplers = shouldUseOldRewriteStructSamplers();
841 
842     // Push a scope in the pool allocator so we can easily reinitialize on flush.
843     mPoolAllocator.push();
844     mOutsideRenderPassCommands.getCommandBuffer().initialize(&mPoolAllocator);
845     mRenderPassCommands.initialize(&mPoolAllocator);
846     ANGLE_TRY(startPrimaryCommandBuffer());
847 
848     if (mGpuEventsEnabled)
849     {
850         // GPU events should only be available if timestamp queries are available.
851         ASSERT(mRenderer->getQueueFamilyProperties().timestampValidBits > 0);
852         // Calculate the difference between CPU and GPU clocks for GPU event reporting.
853         ANGLE_TRY(mGpuEventQueryPool.init(this, VK_QUERY_TYPE_TIMESTAMP,
854                                           vk::kDefaultTimestampQueryPoolSize));
855         ANGLE_TRY(synchronizeCpuGpuTime());
856 
857         mPrimaryBufferCounter++;
858 
859         EventName eventName = GetTraceEventName("Primary", mPrimaryBufferCounter);
860         ANGLE_TRY(traceGpuEvent(&mPrimaryCommands, TRACE_EVENT_PHASE_BEGIN, eventName));
861     }
862 
863     return angle::Result::Continue;
864 }
865 
startPrimaryCommandBuffer()866 angle::Result ContextVk::startPrimaryCommandBuffer()
867 {
868     ANGLE_TRY(mCommandQueue.allocatePrimaryCommandBuffer(this, mCommandPool, &mPrimaryCommands));
869 
870     VkCommandBufferBeginInfo beginInfo = {};
871     beginInfo.sType                    = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
872     beginInfo.flags                    = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
873     beginInfo.pInheritanceInfo         = nullptr;
874     ANGLE_VK_TRY(this, mPrimaryCommands.begin(beginInfo));
875 
876     mHasPrimaryCommands = false;
877     return angle::Result::Continue;
878 }
879 
flush(const gl::Context * context)880 angle::Result ContextVk::flush(const gl::Context *context)
881 {
882     return flushImpl(nullptr);
883 }
884 
finish(const gl::Context * context)885 angle::Result ContextVk::finish(const gl::Context *context)
886 {
887     return finishImpl();
888 }
889 
setupDraw(const gl::Context * context,gl::PrimitiveMode mode,GLint firstVertexOrInvalid,GLsizei vertexOrIndexCount,GLsizei instanceCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,DirtyBits dirtyBitMask,vk::CommandBuffer ** commandBufferOut)890 angle::Result ContextVk::setupDraw(const gl::Context *context,
891                                    gl::PrimitiveMode mode,
892                                    GLint firstVertexOrInvalid,
893                                    GLsizei vertexOrIndexCount,
894                                    GLsizei instanceCount,
895                                    gl::DrawElementsType indexTypeOrInvalid,
896                                    const void *indices,
897                                    DirtyBits dirtyBitMask,
898                                    vk::CommandBuffer **commandBufferOut)
899 {
900     // Set any dirty bits that depend on draw call parameters or other objects.
901     if (mode != mCurrentDrawMode)
902     {
903         invalidateCurrentGraphicsPipeline();
904         mCurrentDrawMode = mode;
905         mGraphicsPipelineDesc->updateTopology(&mGraphicsPipelineTransition, mCurrentDrawMode);
906     }
907 
908     // Must be called before the command buffer is started. Can call finish.
909     if (mVertexArray->getStreamingVertexAttribsMask().any())
910     {
911         // All client attribs & any emulated buffered attribs will be updated
912         ANGLE_TRY(mVertexArray->updateStreamedAttribs(context, firstVertexOrInvalid,
913                                                       vertexOrIndexCount, instanceCount,
914                                                       indexTypeOrInvalid, indices));
915 
916         mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
917     }
918 
919     // This could be improved using a dirty bit. But currently it's slower to use a handler
920     // function than an inlined if. We should probably replace the dirty bit dispatch table
921     // with a switch with inlined handler functions.
922     // TODO(jmadill): Use dirty bit. http://anglebug.com/3014
923     if (!mRenderPassCommandBuffer)
924     {
925         gl::Rectangle scissoredRenderArea = mDrawFramebuffer->getScissoredRenderArea(this);
926         ANGLE_TRY(startRenderPass(scissoredRenderArea));
927     }
928 
929     // We keep a local copy of the command buffer. It's possible that some state changes could
930     // trigger a command buffer invalidation. The local copy ensures we retain the reference.
931     // Command buffers are pool allocated and only deleted after submit. Thus we know the
932     // command buffer will still be valid for the duration of this API call.
933     *commandBufferOut = mRenderPassCommandBuffer;
934     ASSERT(*commandBufferOut);
935 
936     if (mProgram && mProgram->dirtyUniforms())
937     {
938         ANGLE_TRY(mProgram->updateUniforms(this));
939         mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
940     }
941     else if (mProgramPipeline && mProgramPipeline->dirtyUniforms(getState()))
942     {
943         ANGLE_TRY(mProgramPipeline->updateUniforms(this));
944         mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
945     }
946 
947     // Update transform feedback offsets on every draw call.
948     if (mState.isTransformFeedbackActiveUnpaused())
949     {
950         ASSERT(firstVertexOrInvalid != -1);
951         mXfbBaseVertex             = firstVertexOrInvalid;
952         mXfbVertexCountPerInstance = vertexOrIndexCount;
953         invalidateGraphicsDriverUniforms();
954     }
955 
956     DirtyBits dirtyBits = mGraphicsDirtyBits & dirtyBitMask;
957 
958     if (dirtyBits.none())
959         return angle::Result::Continue;
960 
961     // Flush any relevant dirty bits.
962     for (size_t dirtyBit : dirtyBits)
963     {
964         ASSERT(mGraphicsDirtyBitHandlers[dirtyBit]);
965         ANGLE_TRY((this->*mGraphicsDirtyBitHandlers[dirtyBit])(context, *commandBufferOut));
966     }
967 
968     mGraphicsDirtyBits &= ~dirtyBitMask;
969 
970     return angle::Result::Continue;
971 }
972 
setupIndexedDraw(const gl::Context * context,gl::PrimitiveMode mode,GLsizei indexCount,GLsizei instanceCount,gl::DrawElementsType indexType,const void * indices,vk::CommandBuffer ** commandBufferOut)973 angle::Result ContextVk::setupIndexedDraw(const gl::Context *context,
974                                           gl::PrimitiveMode mode,
975                                           GLsizei indexCount,
976                                           GLsizei instanceCount,
977                                           gl::DrawElementsType indexType,
978                                           const void *indices,
979                                           vk::CommandBuffer **commandBufferOut)
980 {
981     ASSERT(mode != gl::PrimitiveMode::LineLoop);
982 
983     if (indexType != mCurrentDrawElementsType)
984     {
985         mCurrentDrawElementsType = indexType;
986         setIndexBufferDirty();
987     }
988 
989     const gl::Buffer *elementArrayBuffer = mVertexArray->getState().getElementArrayBuffer();
990     if (!elementArrayBuffer)
991     {
992         mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
993         ANGLE_TRY(mVertexArray->convertIndexBufferCPU(this, indexType, indexCount, indices));
994     }
995     else
996     {
997         if (indices != mLastIndexBufferOffset)
998         {
999             mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
1000             mLastIndexBufferOffset = indices;
1001             mVertexArray->updateCurrentElementArrayBufferOffset(mLastIndexBufferOffset);
1002         }
1003         if (shouldConvertUint8VkIndexType(indexType) && mGraphicsDirtyBits[DIRTY_BIT_INDEX_BUFFER])
1004         {
1005             BufferVk *bufferVk             = vk::GetImpl(elementArrayBuffer);
1006             vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
1007 
1008             if (bufferHelper.isHostVisible() &&
1009                 !bufferHelper.isCurrentlyInUse(getLastCompletedQueueSerial()))
1010             {
1011                 uint8_t *src = nullptr;
1012                 ANGLE_TRY(bufferVk->mapImpl(this, reinterpret_cast<void **>(&src)));
1013                 src += reinterpret_cast<uintptr_t>(indices);
1014                 const size_t byteCount = static_cast<size_t>(elementArrayBuffer->getSize()) -
1015                                          reinterpret_cast<uintptr_t>(indices);
1016                 ANGLE_TRY(mVertexArray->convertIndexBufferCPU(this, indexType, byteCount, src));
1017                 ANGLE_TRY(bufferVk->unmapImpl(this));
1018             }
1019             else
1020             {
1021                 ANGLE_TRY(mVertexArray->convertIndexBufferGPU(this, bufferVk, indices));
1022             }
1023         }
1024     }
1025 
1026     return setupDraw(context, mode, 0, indexCount, instanceCount, indexType, indices,
1027                      mIndexedDirtyBitsMask, commandBufferOut);
1028 }
1029 
setupIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,DirtyBits dirtyBitMask,vk::BufferHelper * indirectBuffer,VkDeviceSize indirectBufferOffset,vk::CommandBuffer ** commandBufferOut)1030 angle::Result ContextVk::setupIndirectDraw(const gl::Context *context,
1031                                            gl::PrimitiveMode mode,
1032                                            DirtyBits dirtyBitMask,
1033                                            vk::BufferHelper *indirectBuffer,
1034                                            VkDeviceSize indirectBufferOffset,
1035                                            vk::CommandBuffer **commandBufferOut)
1036 {
1037     GLint firstVertex     = -1;
1038     GLsizei vertexCount   = 0;
1039     GLsizei instanceCount = 1;
1040 
1041     mRenderPassCommands.bufferRead(&mResourceUseList, VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
1042                                    indirectBuffer);
1043 
1044     ANGLE_TRY(setupDraw(context, mode, firstVertex, vertexCount, instanceCount,
1045                         gl::DrawElementsType::InvalidEnum, nullptr, dirtyBitMask,
1046                         commandBufferOut));
1047 
1048     return angle::Result::Continue;
1049 }
1050 
setupIndexedIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType indexType,vk::BufferHelper * indirectBuffer,VkDeviceSize indirectBufferOffset,vk::CommandBuffer ** commandBufferOut)1051 angle::Result ContextVk::setupIndexedIndirectDraw(const gl::Context *context,
1052                                                   gl::PrimitiveMode mode,
1053                                                   gl::DrawElementsType indexType,
1054                                                   vk::BufferHelper *indirectBuffer,
1055                                                   VkDeviceSize indirectBufferOffset,
1056                                                   vk::CommandBuffer **commandBufferOut)
1057 {
1058     ASSERT(mode != gl::PrimitiveMode::LineLoop);
1059 
1060     if (indexType != mCurrentDrawElementsType)
1061     {
1062         mCurrentDrawElementsType = indexType;
1063         setIndexBufferDirty();
1064     }
1065 
1066     return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, indirectBuffer,
1067                              indirectBufferOffset, commandBufferOut);
1068 }
1069 
setupLineLoopIndexedIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType indexType,vk::BufferHelper * srcIndirectBuf,VkDeviceSize indirectBufferOffset,vk::CommandBuffer ** commandBufferOut,vk::BufferHelper ** indirectBufferOut,VkDeviceSize * indirectBufferOffsetOut)1070 angle::Result ContextVk::setupLineLoopIndexedIndirectDraw(const gl::Context *context,
1071                                                           gl::PrimitiveMode mode,
1072                                                           gl::DrawElementsType indexType,
1073                                                           vk::BufferHelper *srcIndirectBuf,
1074                                                           VkDeviceSize indirectBufferOffset,
1075                                                           vk::CommandBuffer **commandBufferOut,
1076                                                           vk::BufferHelper **indirectBufferOut,
1077                                                           VkDeviceSize *indirectBufferOffsetOut)
1078 {
1079     ASSERT(mode == gl::PrimitiveMode::LineLoop);
1080 
1081     vk::BufferHelper *dstIndirectBuf  = nullptr;
1082     VkDeviceSize dstIndirectBufOffset = 0;
1083 
1084     ANGLE_TRY(mVertexArray->handleLineLoopIndexIndirect(this, indexType, srcIndirectBuf,
1085                                                         indirectBufferOffset, &dstIndirectBuf,
1086                                                         &dstIndirectBufOffset));
1087 
1088     *indirectBufferOut       = dstIndirectBuf;
1089     *indirectBufferOffsetOut = dstIndirectBufOffset;
1090 
1091     if (indexType != mCurrentDrawElementsType)
1092     {
1093         mCurrentDrawElementsType = indexType;
1094         setIndexBufferDirty();
1095     }
1096 
1097     return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, dstIndirectBuf,
1098                              dstIndirectBufOffset, commandBufferOut);
1099 }
1100 
setupLineLoopIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,vk::BufferHelper * indirectBuffer,VkDeviceSize indirectBufferOffset,vk::CommandBuffer ** commandBufferOut,vk::BufferHelper ** indirectBufferOut,VkDeviceSize * indirectBufferOffsetOut)1101 angle::Result ContextVk::setupLineLoopIndirectDraw(const gl::Context *context,
1102                                                    gl::PrimitiveMode mode,
1103                                                    vk::BufferHelper *indirectBuffer,
1104                                                    VkDeviceSize indirectBufferOffset,
1105                                                    vk::CommandBuffer **commandBufferOut,
1106                                                    vk::BufferHelper **indirectBufferOut,
1107                                                    VkDeviceSize *indirectBufferOffsetOut)
1108 {
1109     ASSERT(mode == gl::PrimitiveMode::LineLoop);
1110 
1111     vk::BufferHelper *indirectBufferHelperOut = nullptr;
1112 
1113     ANGLE_TRY(mVertexArray->handleLineLoopIndirectDraw(
1114         context, indirectBuffer, indirectBufferOffset, &indirectBufferHelperOut,
1115         indirectBufferOffsetOut));
1116 
1117     *indirectBufferOut = indirectBufferHelperOut;
1118 
1119     if (gl::DrawElementsType::UnsignedInt != mCurrentDrawElementsType)
1120     {
1121         mCurrentDrawElementsType = gl::DrawElementsType::UnsignedInt;
1122         setIndexBufferDirty();
1123     }
1124 
1125     return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, indirectBufferHelperOut,
1126                              *indirectBufferOffsetOut, commandBufferOut);
1127 }
1128 
setupLineLoopDraw(const gl::Context * context,gl::PrimitiveMode mode,GLint firstVertex,GLsizei vertexOrIndexCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,vk::CommandBuffer ** commandBufferOut,uint32_t * numIndicesOut)1129 angle::Result ContextVk::setupLineLoopDraw(const gl::Context *context,
1130                                            gl::PrimitiveMode mode,
1131                                            GLint firstVertex,
1132                                            GLsizei vertexOrIndexCount,
1133                                            gl::DrawElementsType indexTypeOrInvalid,
1134                                            const void *indices,
1135                                            vk::CommandBuffer **commandBufferOut,
1136                                            uint32_t *numIndicesOut)
1137 {
1138     ANGLE_TRY(mVertexArray->handleLineLoop(this, firstVertex, vertexOrIndexCount,
1139                                            indexTypeOrInvalid, indices, numIndicesOut));
1140     setIndexBufferDirty();
1141     mCurrentDrawElementsType = indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum
1142                                    ? indexTypeOrInvalid
1143                                    : gl::DrawElementsType::UnsignedInt;
1144     return setupDraw(context, mode, firstVertex, vertexOrIndexCount, 1, indexTypeOrInvalid, indices,
1145                      mIndexedDirtyBitsMask, commandBufferOut);
1146 }
1147 
setupDispatch(const gl::Context * context,vk::CommandBuffer ** commandBufferOut)1148 angle::Result ContextVk::setupDispatch(const gl::Context *context,
1149                                        vk::CommandBuffer **commandBufferOut)
1150 {
1151     // |setupDispatch| and |setupDraw| are special in that they flush dirty bits. Therefore they
1152     // don't use the same APIs to record commands as the functions outside ContextVk.
1153     // The following ensures prior commands are flushed before we start processing dirty bits.
1154     flushOutsideRenderPassCommands();
1155     ANGLE_TRY(endRenderPass());
1156     *commandBufferOut = &mOutsideRenderPassCommands.getCommandBuffer();
1157 
1158     if (mProgram && mProgram->dirtyUniforms())
1159     {
1160         ANGLE_TRY(mProgram->updateUniforms(this));
1161         mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
1162     }
1163     else if (mProgramPipeline && mProgramPipeline->dirtyUniforms(getState()))
1164     {
1165         ANGLE_TRY(mProgramPipeline->updateUniforms(this));
1166         mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
1167     }
1168 
1169     DirtyBits dirtyBits = mComputeDirtyBits;
1170 
1171     // Flush any relevant dirty bits.
1172     for (size_t dirtyBit : dirtyBits)
1173     {
1174         ASSERT(mComputeDirtyBitHandlers[dirtyBit]);
1175         ANGLE_TRY((this->*mComputeDirtyBitHandlers[dirtyBit])(context, *commandBufferOut));
1176     }
1177 
1178     mComputeDirtyBits.reset();
1179 
1180     return angle::Result::Continue;
1181 }
1182 
handleDirtyGraphicsDefaultAttribs(const gl::Context * context,vk::CommandBuffer * commandBuffer)1183 angle::Result ContextVk::handleDirtyGraphicsDefaultAttribs(const gl::Context *context,
1184                                                            vk::CommandBuffer *commandBuffer)
1185 {
1186     ASSERT(mDirtyDefaultAttribsMask.any());
1187 
1188     for (size_t attribIndex : mDirtyDefaultAttribsMask)
1189     {
1190         ANGLE_TRY(updateDefaultAttribute(attribIndex));
1191     }
1192 
1193     mDirtyDefaultAttribsMask.reset();
1194     return angle::Result::Continue;
1195 }
1196 
handleDirtyGraphicsPipeline(const gl::Context * context,vk::CommandBuffer * commandBuffer)1197 angle::Result ContextVk::handleDirtyGraphicsPipeline(const gl::Context *context,
1198                                                      vk::CommandBuffer *commandBuffer)
1199 {
1200     ASSERT(mExecutable);
1201     mExecutable->updateEarlyFragmentTestsOptimization(this);
1202 
1203     if (!mCurrentGraphicsPipeline)
1204     {
1205         const vk::GraphicsPipelineDesc *descPtr;
1206 
1207         // Draw call shader patching, shader compilation, and pipeline cache query.
1208         ANGLE_TRY(mExecutable->getGraphicsPipeline(
1209             this, mCurrentDrawMode, *mGraphicsPipelineDesc,
1210             context->getState().getProgramExecutable()->getNonBuiltinAttribLocationsMask(),
1211             &descPtr, &mCurrentGraphicsPipeline));
1212         mGraphicsPipelineTransition.reset();
1213     }
1214     else if (mGraphicsPipelineTransition.any())
1215     {
1216         if (!mCurrentGraphicsPipeline->findTransition(
1217                 mGraphicsPipelineTransition, *mGraphicsPipelineDesc, &mCurrentGraphicsPipeline))
1218         {
1219             vk::PipelineHelper *oldPipeline = mCurrentGraphicsPipeline;
1220             const vk::GraphicsPipelineDesc *descPtr;
1221 
1222             ANGLE_TRY(mExecutable->getGraphicsPipeline(
1223                 this, mCurrentDrawMode, *mGraphicsPipelineDesc,
1224                 context->getState().getProgramExecutable()->getNonBuiltinAttribLocationsMask(),
1225                 &descPtr, &mCurrentGraphicsPipeline));
1226 
1227             oldPipeline->addTransition(mGraphicsPipelineTransition, descPtr,
1228                                        mCurrentGraphicsPipeline);
1229         }
1230 
1231         mGraphicsPipelineTransition.reset();
1232     }
1233     mRenderPassCommands.pauseTransformFeedbackIfStarted();
1234     commandBuffer->bindGraphicsPipeline(mCurrentGraphicsPipeline->getPipeline());
1235     // Update the queue serial for the pipeline object.
1236     ASSERT(mCurrentGraphicsPipeline && mCurrentGraphicsPipeline->valid());
1237     mCurrentGraphicsPipeline->updateSerial(getCurrentQueueSerial());
1238     return angle::Result::Continue;
1239 }
1240 
handleDirtyComputePipeline(const gl::Context * context,vk::CommandBuffer * commandBuffer)1241 angle::Result ContextVk::handleDirtyComputePipeline(const gl::Context *context,
1242                                                     vk::CommandBuffer *commandBuffer)
1243 {
1244     if (!mCurrentComputePipeline)
1245     {
1246         ASSERT(mExecutable);
1247         ANGLE_TRY(mExecutable->getComputePipeline(this, &mCurrentComputePipeline));
1248     }
1249 
1250     commandBuffer->bindComputePipeline(mCurrentComputePipeline->get());
1251     mCurrentComputePipeline->updateSerial(getCurrentQueueSerial());
1252 
1253     return angle::Result::Continue;
1254 }
1255 
handleDirtyTexturesImpl(CommandBufferHelper * commandBufferHelper)1256 ANGLE_INLINE angle::Result ContextVk::handleDirtyTexturesImpl(
1257     CommandBufferHelper *commandBufferHelper)
1258 {
1259     const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1260     ASSERT(executable);
1261     const gl::ActiveTextureMask &activeTextures = executable->getActiveSamplersMask();
1262 
1263     for (size_t textureUnit : activeTextures)
1264     {
1265         const vk::TextureUnit &unit = mActiveTextures[textureUnit];
1266         TextureVk *textureVk        = unit.texture;
1267         vk::ImageHelper &image      = textureVk->getImage();
1268 
1269         // The image should be flushed and ready to use at this point. There may still be
1270         // lingering staged updates in its staging buffer for unused texture mip levels or
1271         // layers. Therefore we can't verify it has no staged updates right here.
1272 
1273         // Select the appropriate vk::ImageLayout depending on whether the texture is also bound as
1274         // a GL image, and whether the program is a compute or graphics shader.
1275         vk::ImageLayout textureLayout;
1276         if (textureVk->isBoundAsImageTexture(mState.getContextID()))
1277         {
1278             textureLayout = executable->isCompute() ? vk::ImageLayout::ComputeShaderWrite
1279                                                     : vk::ImageLayout::AllGraphicsShadersReadWrite;
1280         }
1281         else
1282         {
1283             gl::ShaderBitSet shaderBits =
1284                 executable->getSamplerShaderBitsForTextureUnitIndex(textureUnit);
1285             if (shaderBits.any())
1286             {
1287                 gl::ShaderType shader =
1288                     static_cast<gl::ShaderType>(gl::ScanForward(shaderBits.bits()));
1289                 shaderBits.reset(shader);
1290                 // If we have multiple shader accessing it, we barrier against all shader stage read
1291                 // given that we only support vertex/frag shaders
1292                 if (shaderBits.any())
1293                 {
1294                     textureLayout = vk::ImageLayout::AllGraphicsShadersReadOnly;
1295                 }
1296                 else
1297                 {
1298                     textureLayout = kShaderReadOnlyImageLayouts[shader];
1299                 }
1300             }
1301             else
1302             {
1303                 textureLayout = vk::ImageLayout::AllGraphicsShadersReadOnly;
1304             }
1305         }
1306         // Ensure the image is in read-only layout
1307         commandBufferHelper->imageRead(&mResourceUseList, image.getAspectFlags(), textureLayout,
1308                                        &image);
1309 
1310         textureVk->retainImageViews(&mResourceUseList);
1311 
1312         if (unit.sampler)
1313         {
1314             unit.sampler->retain(&mResourceUseList);
1315         }
1316         else
1317         {
1318             textureVk->retainSampler(&mResourceUseList);
1319         }
1320     }
1321 
1322     if (executable->hasTextures())
1323     {
1324         ANGLE_TRY(mExecutable->updateTexturesDescriptorSet(this));
1325     }
1326 
1327     return angle::Result::Continue;
1328 }
1329 
handleDirtyGraphicsTextures(const gl::Context * context,vk::CommandBuffer * commandBuffer)1330 angle::Result ContextVk::handleDirtyGraphicsTextures(const gl::Context *context,
1331                                                      vk::CommandBuffer *commandBuffer)
1332 {
1333     return handleDirtyTexturesImpl(&mRenderPassCommands);
1334 }
1335 
handleDirtyComputeTextures(const gl::Context * context,vk::CommandBuffer * commandBuffer)1336 angle::Result ContextVk::handleDirtyComputeTextures(const gl::Context *context,
1337                                                     vk::CommandBuffer *commandBuffer)
1338 {
1339     return handleDirtyTexturesImpl(&mOutsideRenderPassCommands);
1340 }
1341 
handleDirtyGraphicsVertexBuffers(const gl::Context * context,vk::CommandBuffer * commandBuffer)1342 angle::Result ContextVk::handleDirtyGraphicsVertexBuffers(const gl::Context *context,
1343                                                           vk::CommandBuffer *commandBuffer)
1344 {
1345     uint32_t maxAttrib = context->getState().getProgramExecutable()->getMaxActiveAttribLocation();
1346     const gl::AttribArray<VkBuffer> &bufferHandles = mVertexArray->getCurrentArrayBufferHandles();
1347     const gl::AttribArray<VkDeviceSize> &bufferOffsets =
1348         mVertexArray->getCurrentArrayBufferOffsets();
1349 
1350     commandBuffer->bindVertexBuffers(0, maxAttrib, bufferHandles.data(), bufferOffsets.data());
1351 
1352     const gl::AttribArray<vk::BufferHelper *> &arrayBufferResources =
1353         mVertexArray->getCurrentArrayBuffers();
1354 
1355     // Mark all active vertex buffers as accessed.
1356     const gl::ProgramExecutable *executable = context->getState().getProgramExecutable();
1357     gl::AttributesMask attribsMask          = executable->getActiveAttribLocationsMask();
1358     for (size_t attribIndex : attribsMask)
1359     {
1360         vk::BufferHelper *arrayBuffer = arrayBufferResources[attribIndex];
1361         if (arrayBuffer)
1362         {
1363             mRenderPassCommands.bufferRead(&mResourceUseList, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
1364                                            arrayBuffer);
1365         }
1366     }
1367 
1368     return angle::Result::Continue;
1369 }
1370 
handleDirtyGraphicsIndexBuffer(const gl::Context * context,vk::CommandBuffer * commandBuffer)1371 angle::Result ContextVk::handleDirtyGraphicsIndexBuffer(const gl::Context *context,
1372                                                         vk::CommandBuffer *commandBuffer)
1373 {
1374     vk::BufferHelper *elementArrayBuffer = mVertexArray->getCurrentElementArrayBuffer();
1375     ASSERT(elementArrayBuffer != nullptr);
1376 
1377     commandBuffer->bindIndexBuffer(elementArrayBuffer->getBuffer(),
1378                                    mVertexArray->getCurrentElementArrayBufferOffset(),
1379                                    getVkIndexType(mCurrentDrawElementsType));
1380 
1381     mRenderPassCommands.bufferRead(&mResourceUseList, VK_ACCESS_INDEX_READ_BIT, elementArrayBuffer);
1382 
1383     return angle::Result::Continue;
1384 }
1385 
handleDirtyShaderResourcesImpl(const gl::Context * context,CommandBufferHelper * commandBufferHelper)1386 ANGLE_INLINE angle::Result ContextVk::handleDirtyShaderResourcesImpl(
1387     const gl::Context *context,
1388     CommandBufferHelper *commandBufferHelper)
1389 {
1390     const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1391     ASSERT(executable);
1392 
1393     if (executable->hasImages())
1394     {
1395         ANGLE_TRY(updateActiveImages(context, commandBufferHelper));
1396     }
1397 
1398     if (executable->hasUniformBuffers() || executable->hasStorageBuffers() ||
1399         executable->hasAtomicCounterBuffers() || executable->hasImages())
1400     {
1401         ANGLE_TRY(mExecutable->updateShaderResourcesDescriptorSet(this, &mResourceUseList,
1402                                                                   commandBufferHelper));
1403     }
1404     return angle::Result::Continue;
1405 }
1406 
handleDirtyGraphicsShaderResources(const gl::Context * context,vk::CommandBuffer * commandBuffer)1407 angle::Result ContextVk::handleDirtyGraphicsShaderResources(const gl::Context *context,
1408                                                             vk::CommandBuffer *commandBuffer)
1409 {
1410     return handleDirtyShaderResourcesImpl(context, &mRenderPassCommands);
1411 }
1412 
handleDirtyComputeShaderResources(const gl::Context * context,vk::CommandBuffer * commandBuffer)1413 angle::Result ContextVk::handleDirtyComputeShaderResources(const gl::Context *context,
1414                                                            vk::CommandBuffer *commandBuffer)
1415 {
1416     return handleDirtyShaderResourcesImpl(context, &mOutsideRenderPassCommands);
1417 }
1418 
handleDirtyGraphicsTransformFeedbackBuffersEmulation(const gl::Context * context,vk::CommandBuffer * commandBuffer)1419 angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffersEmulation(
1420     const gl::Context *context,
1421     vk::CommandBuffer *commandBuffer)
1422 {
1423     const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1424     ASSERT(executable);
1425 
1426     if (executable->hasTransformFeedbackOutput() && mState.isTransformFeedbackActive())
1427     {
1428         size_t bufferCount = executable->getTransformFeedbackBufferCount(mState);
1429         const std::vector<gl::OffsetBindingPointer<gl::Buffer>> &xfbBuffers =
1430             mState.getCurrentTransformFeedback()->getIndexedBuffers();
1431 
1432         for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
1433         {
1434             const gl::OffsetBindingPointer<gl::Buffer> &xfbBuffer = xfbBuffers[bufferIndex];
1435             gl::Buffer *buffer                                    = xfbBuffer.get();
1436             ASSERT(buffer != nullptr);
1437             BufferVk *bufferVk             = vk::GetImpl(buffer);
1438             vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
1439 
1440             mRenderPassCommands.bufferWrite(
1441                 &mResourceUseList, VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, &bufferHelper);
1442         }
1443 
1444         // TODO(http://anglebug.com/3570): Need to update to handle Program Pipelines
1445         ANGLE_TRY(mProgram->getExecutable().updateTransformFeedbackDescriptorSet(
1446             mProgram->getState(), mProgram->getDefaultUniformBlocks(), this));
1447     }
1448     return angle::Result::Continue;
1449 }
1450 
handleDirtyGraphicsTransformFeedbackBuffersExtension(const gl::Context * context,vk::CommandBuffer * commandBuffer)1451 angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffersExtension(
1452     const gl::Context *context,
1453     vk::CommandBuffer *commandBuffer)
1454 {
1455     const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1456     ASSERT(executable);
1457 
1458     if (!executable->hasTransformFeedbackOutput() || !mState.isTransformFeedbackActive())
1459         return angle::Result::Continue;
1460 
1461     size_t bufferIndex                       = 0;
1462     TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(mState.getCurrentTransformFeedback());
1463 
1464     size_t bufferCount = executable->getTransformFeedbackBufferCount(mState);
1465     gl::TransformFeedbackBuffersArray<VkBuffer> bufferHandles;
1466 
1467     const std::vector<gl::OffsetBindingPointer<gl::Buffer>> &xfbBuffers =
1468         mState.getCurrentTransformFeedback()->getIndexedBuffers();
1469 
1470     for (bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
1471     {
1472         const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = xfbBuffers[bufferIndex];
1473         gl::Buffer *buffer                                        = bufferBinding.get();
1474         ASSERT(buffer != nullptr);
1475         BufferVk *bufferVk = vk::GetImpl(buffer);
1476 
1477         vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
1478         bufferHandles[bufferIndex]     = bufferHelper.getBuffer().getHandle();
1479 
1480         mRenderPassCommands.bufferWrite(&mResourceUseList,
1481                                         VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, &bufferHelper);
1482     }
1483 
1484     const TransformFeedbackBufferRange &xfbBufferRangeExtension =
1485         transformFeedbackVk->getTransformFeedbackBufferRange();
1486 
1487     commandBuffer->bindTransformFeedbackBuffers(
1488         static_cast<uint32_t>(bufferCount), bufferHandles.data(),
1489         xfbBufferRangeExtension.offsets.data(), xfbBufferRangeExtension.sizes.data());
1490 
1491     return angle::Result::Continue;
1492 }
1493 
handleDirtyGraphicsTransformFeedbackState(const gl::Context * context,vk::CommandBuffer * commandBuffer)1494 angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackState(const gl::Context *context,
1495                                                                    vk::CommandBuffer *commandBuffer)
1496 {
1497     const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1498     ASSERT(executable);
1499 
1500     if (!executable->hasTransformFeedbackOutput() || !mState.isTransformFeedbackActiveUnpaused())
1501         return angle::Result::Continue;
1502 
1503     TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(mState.getCurrentTransformFeedback());
1504 
1505     // We should have same number of counter buffers as xfb buffers have
1506     size_t bufferCount = executable->getTransformFeedbackBufferCount(mState);
1507     const gl::TransformFeedbackBuffersArray<VkBuffer> &counterBufferHandles =
1508         transformFeedbackVk->getCounterBufferHandles();
1509 
1510     bool rebindBuffer = transformFeedbackVk->getTransformFeedbackBufferRebindState();
1511 
1512     mRenderPassCommands.beginTransformFeedback(bufferCount, counterBufferHandles.data(),
1513                                                rebindBuffer);
1514 
1515     transformFeedbackVk->unsetTransformFeedbackBufferRebindState();
1516 
1517     return angle::Result::Continue;
1518 }
1519 
handleDirtyGraphicsTransformFeedbackResume(const gl::Context * context,vk::CommandBuffer * commandBuffer)1520 angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackResume(
1521     const gl::Context *context,
1522     vk::CommandBuffer *commandBuffer)
1523 {
1524     mRenderPassCommands.resumeTransformFeedbackIfStarted();
1525     return angle::Result::Continue;
1526 }
1527 
handleDirtyDescriptorSets(const gl::Context * context,vk::CommandBuffer * commandBuffer)1528 angle::Result ContextVk::handleDirtyDescriptorSets(const gl::Context *context,
1529                                                    vk::CommandBuffer *commandBuffer)
1530 {
1531     ANGLE_TRY(mExecutable->updateDescriptorSets(this, commandBuffer));
1532     return angle::Result::Continue;
1533 }
1534 
submitFrame(const VkSubmitInfo & submitInfo,vk::PrimaryCommandBuffer && commandBuffer)1535 angle::Result ContextVk::submitFrame(const VkSubmitInfo &submitInfo,
1536                                      vk::PrimaryCommandBuffer &&commandBuffer)
1537 {
1538     // Update overlay if active.
1539     gl::RunningGraphWidget *renderPassCount =
1540         mState.getOverlay()->getRunningGraphWidget(gl::WidgetId::VulkanRenderPassCount);
1541     renderPassCount->add(mRenderPassCommands.getAndResetCounter());
1542     renderPassCount->next();
1543 
1544     if (kEnableCommandStreamDiagnostics)
1545     {
1546         dumpCommandStreamDiagnostics();
1547     }
1548 
1549     ANGLE_TRY(ensureSubmitFenceInitialized());
1550     ANGLE_TRY(mCommandQueue.submitFrame(this, mContextPriority, submitInfo, mSubmitFence,
1551                                         &mCurrentGarbage, &mCommandPool, std::move(commandBuffer)));
1552 
1553     // we need to explicitly notify every other Context using this VkQueue that their current
1554     // command buffer is no longer valid.
1555     onRenderPassFinished();
1556     mComputeDirtyBits |= mNewComputeCommandBufferDirtyBits;
1557 
1558     // Make sure a new fence is created for the next submission.
1559     mRenderer->resetSharedFence(&mSubmitFence);
1560 
1561     if (mGpuEventsEnabled)
1562     {
1563         ANGLE_TRY(checkCompletedGpuEvents());
1564     }
1565 
1566     return angle::Result::Continue;
1567 }
1568 
synchronizeCpuGpuTime()1569 angle::Result ContextVk::synchronizeCpuGpuTime()
1570 {
1571     ASSERT(mGpuEventsEnabled);
1572 
1573     angle::PlatformMethods *platform = ANGLEPlatformCurrent();
1574     ASSERT(platform);
1575 
1576     // To synchronize CPU and GPU times, we need to get the CPU timestamp as close as possible
1577     // to the GPU timestamp.  The process of getting the GPU timestamp is as follows:
1578     //
1579     //             CPU                            GPU
1580     //
1581     //     Record command buffer
1582     //     with timestamp query
1583     //
1584     //     Submit command buffer
1585     //
1586     //     Post-submission work             Begin execution
1587     //
1588     //            ????                    Write timestamp Tgpu
1589     //
1590     //            ????                       End execution
1591     //
1592     //            ????                    Return query results
1593     //
1594     //            ????
1595     //
1596     //       Get query results
1597     //
1598     // The areas of unknown work (????) on the CPU indicate that the CPU may or may not have
1599     // finished post-submission work while the GPU is executing in parallel. With no further
1600     // work, querying CPU timestamps before submission and after getting query results give the
1601     // bounds to Tgpu, which could be quite large.
1602     //
1603     // Using VkEvents, the GPU can be made to wait for the CPU and vice versa, in an effort to
1604     // reduce this range. This function implements the following procedure:
1605     //
1606     //             CPU                            GPU
1607     //
1608     //     Record command buffer
1609     //     with timestamp query
1610     //
1611     //     Submit command buffer
1612     //
1613     //     Post-submission work             Begin execution
1614     //
1615     //            ????                    Set Event GPUReady
1616     //
1617     //    Wait on Event GPUReady         Wait on Event CPUReady
1618     //
1619     //       Get CPU Time Ts             Wait on Event CPUReady
1620     //
1621     //      Set Event CPUReady           Wait on Event CPUReady
1622     //
1623     //      Get CPU Time Tcpu              Get GPU Time Tgpu
1624     //
1625     //    Wait on Event GPUDone            Set Event GPUDone
1626     //
1627     //       Get CPU Time Te                 End Execution
1628     //
1629     //            Idle                    Return query results
1630     //
1631     //      Get query results
1632     //
1633     // If Te-Ts > epsilon, a GPU or CPU interruption can be assumed and the operation can be
1634     // retried.  Once Te-Ts < epsilon, Tcpu can be taken to presumably match Tgpu.  Finding an
1635     // epsilon that's valid for all devices may be difficult, so the loop can be performed only
1636     // a limited number of times and the Tcpu,Tgpu pair corresponding to smallest Te-Ts used for
1637     // calibration.
1638     //
1639     // Note: Once VK_EXT_calibrated_timestamps is ubiquitous, this should be redone.
1640 
1641     // Make sure nothing is running
1642     ASSERT(!hasRecordedCommands());
1643 
1644     ANGLE_TRACE_EVENT0("gpu.angle", "RendererVk::synchronizeCpuGpuTime");
1645 
1646     // Create a query used to receive the GPU timestamp
1647     vk::QueryHelper timestampQuery;
1648     ANGLE_TRY(mGpuEventQueryPool.allocateQuery(this, &timestampQuery));
1649 
1650     // Create the three events
1651     VkEventCreateInfo eventCreateInfo = {};
1652     eventCreateInfo.sType             = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
1653     eventCreateInfo.flags             = 0;
1654 
1655     VkDevice device = getDevice();
1656     vk::DeviceScoped<vk::Event> cpuReady(device), gpuReady(device), gpuDone(device);
1657     ANGLE_VK_TRY(this, cpuReady.get().init(device, eventCreateInfo));
1658     ANGLE_VK_TRY(this, gpuReady.get().init(device, eventCreateInfo));
1659     ANGLE_VK_TRY(this, gpuDone.get().init(device, eventCreateInfo));
1660 
1661     constexpr uint32_t kRetries = 10;
1662 
1663     // Time suffixes used are S for seconds and Cycles for cycles
1664     double tightestRangeS = 1e6f;
1665     double TcpuS          = 0;
1666     uint64_t TgpuCycles   = 0;
1667     for (uint32_t i = 0; i < kRetries; ++i)
1668     {
1669         // Reset the events
1670         ANGLE_VK_TRY(this, cpuReady.get().reset(device));
1671         ANGLE_VK_TRY(this, gpuReady.get().reset(device));
1672         ANGLE_VK_TRY(this, gpuDone.get().reset(device));
1673 
1674         // Record the command buffer
1675         vk::DeviceScoped<vk::PrimaryCommandBuffer> commandBatch(device);
1676         vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get();
1677 
1678         ANGLE_TRY(mCommandQueue.allocatePrimaryCommandBuffer(this, mCommandPool, &commandBuffer));
1679 
1680         VkCommandBufferBeginInfo beginInfo = {};
1681         beginInfo.sType                    = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1682         beginInfo.flags                    = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1683         beginInfo.pInheritanceInfo         = nullptr;
1684 
1685         ANGLE_VK_TRY(this, commandBuffer.begin(beginInfo));
1686 
1687         commandBuffer.setEvent(gpuReady.get().getHandle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
1688         commandBuffer.waitEvents(1, cpuReady.get().ptr(), VK_PIPELINE_STAGE_HOST_BIT,
1689                                  VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, nullptr, 0, nullptr, 0,
1690                                  nullptr);
1691         timestampQuery.writeTimestamp(this, &commandBuffer);
1692         commandBuffer.setEvent(gpuDone.get().getHandle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
1693 
1694         ANGLE_VK_TRY(this, commandBuffer.end());
1695 
1696         // Submit the command buffer
1697         VkSubmitInfo submitInfo = {};
1698         InitializeSubmitInfo(&submitInfo, commandBatch.get(), {}, &mWaitSemaphoreStageMasks,
1699                              nullptr);
1700 
1701         ANGLE_TRY(submitFrame(submitInfo, commandBatch.release()));
1702 
1703         // Wait for GPU to be ready.  This is a short busy wait.
1704         VkResult result = VK_EVENT_RESET;
1705         do
1706         {
1707             result = gpuReady.get().getStatus(device);
1708             if (result != VK_EVENT_SET && result != VK_EVENT_RESET)
1709             {
1710                 ANGLE_VK_TRY(this, result);
1711             }
1712         } while (result == VK_EVENT_RESET);
1713 
1714         double TsS = platform->monotonicallyIncreasingTime(platform);
1715 
1716         // Tell the GPU to go ahead with the timestamp query.
1717         ANGLE_VK_TRY(this, cpuReady.get().set(device));
1718         double cpuTimestampS = platform->monotonicallyIncreasingTime(platform);
1719 
1720         // Wait for GPU to be done.  Another short busy wait.
1721         do
1722         {
1723             result = gpuDone.get().getStatus(device);
1724             if (result != VK_EVENT_SET && result != VK_EVENT_RESET)
1725             {
1726                 ANGLE_VK_TRY(this, result);
1727             }
1728         } while (result == VK_EVENT_RESET);
1729 
1730         double TeS = platform->monotonicallyIncreasingTime(platform);
1731 
1732         // Get the query results
1733         ANGLE_TRY(finishToSerial(getLastSubmittedQueueSerial()));
1734 
1735         uint64_t gpuTimestampCycles = 0;
1736         ANGLE_TRY(timestampQuery.getUint64Result(this, &gpuTimestampCycles));
1737 
1738         // Use the first timestamp queried as origin.
1739         if (mGpuEventTimestampOrigin == 0)
1740         {
1741             mGpuEventTimestampOrigin = gpuTimestampCycles;
1742         }
1743 
1744         // Take these CPU and GPU timestamps if there is better confidence.
1745         double confidenceRangeS = TeS - TsS;
1746         if (confidenceRangeS < tightestRangeS)
1747         {
1748             tightestRangeS = confidenceRangeS;
1749             TcpuS          = cpuTimestampS;
1750             TgpuCycles     = gpuTimestampCycles;
1751         }
1752     }
1753 
1754     mGpuEventQueryPool.freeQuery(this, &timestampQuery);
1755 
1756     // timestampPeriod gives nanoseconds/cycle.
1757     double TgpuS =
1758         (TgpuCycles - mGpuEventTimestampOrigin) *
1759         static_cast<double>(getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod) /
1760         1'000'000'000.0;
1761 
1762     flushGpuEvents(TgpuS, TcpuS);
1763 
1764     mGpuClockSync.gpuTimestampS = TgpuS;
1765     mGpuClockSync.cpuTimestampS = TcpuS;
1766 
1767     return angle::Result::Continue;
1768 }
1769 
traceGpuEventImpl(vk::PrimaryCommandBuffer * commandBuffer,char phase,const EventName & name)1770 angle::Result ContextVk::traceGpuEventImpl(vk::PrimaryCommandBuffer *commandBuffer,
1771                                            char phase,
1772                                            const EventName &name)
1773 {
1774     ASSERT(mGpuEventsEnabled);
1775 
1776     GpuEventQuery gpuEvent;
1777     gpuEvent.name  = name;
1778     gpuEvent.phase = phase;
1779     ANGLE_TRY(mGpuEventQueryPool.allocateQuery(this, &gpuEvent.queryHelper));
1780 
1781     gpuEvent.queryHelper.writeTimestamp(this, commandBuffer);
1782 
1783     mInFlightGpuEventQueries.push_back(std::move(gpuEvent));
1784     return angle::Result::Continue;
1785 }
1786 
checkCompletedGpuEvents()1787 angle::Result ContextVk::checkCompletedGpuEvents()
1788 {
1789     ASSERT(mGpuEventsEnabled);
1790 
1791     angle::PlatformMethods *platform = ANGLEPlatformCurrent();
1792     ASSERT(platform);
1793 
1794     int finishedCount = 0;
1795 
1796     Serial lastCompletedSerial = getLastCompletedQueueSerial();
1797 
1798     for (GpuEventQuery &eventQuery : mInFlightGpuEventQueries)
1799     {
1800         // Only check the timestamp query if the submission has finished.
1801         if (eventQuery.queryHelper.getStoredQueueSerial() > lastCompletedSerial)
1802         {
1803             break;
1804         }
1805 
1806         // See if the results are available.
1807         uint64_t gpuTimestampCycles = 0;
1808         bool available              = false;
1809         ANGLE_TRY(eventQuery.queryHelper.getUint64ResultNonBlocking(this, &gpuTimestampCycles,
1810                                                                     &available));
1811         if (!available)
1812         {
1813             break;
1814         }
1815 
1816         mGpuEventQueryPool.freeQuery(this, &eventQuery.queryHelper);
1817 
1818         GpuEvent gpuEvent;
1819         gpuEvent.gpuTimestampCycles = gpuTimestampCycles;
1820         gpuEvent.name               = eventQuery.name;
1821         gpuEvent.phase              = eventQuery.phase;
1822 
1823         mGpuEvents.emplace_back(gpuEvent);
1824 
1825         ++finishedCount;
1826     }
1827 
1828     mInFlightGpuEventQueries.erase(mInFlightGpuEventQueries.begin(),
1829                                    mInFlightGpuEventQueries.begin() + finishedCount);
1830 
1831     return angle::Result::Continue;
1832 }
1833 
flushGpuEvents(double nextSyncGpuTimestampS,double nextSyncCpuTimestampS)1834 void ContextVk::flushGpuEvents(double nextSyncGpuTimestampS, double nextSyncCpuTimestampS)
1835 {
1836     if (mGpuEvents.empty())
1837     {
1838         return;
1839     }
1840 
1841     angle::PlatformMethods *platform = ANGLEPlatformCurrent();
1842     ASSERT(platform);
1843 
1844     // Find the slope of the clock drift for adjustment
1845     double lastGpuSyncTimeS  = mGpuClockSync.gpuTimestampS;
1846     double lastGpuSyncDiffS  = mGpuClockSync.cpuTimestampS - mGpuClockSync.gpuTimestampS;
1847     double gpuSyncDriftSlope = 0;
1848 
1849     double nextGpuSyncTimeS = nextSyncGpuTimestampS;
1850     double nextGpuSyncDiffS = nextSyncCpuTimestampS - nextSyncGpuTimestampS;
1851 
1852     // No gpu trace events should have been generated before the clock sync, so if there is no
1853     // "previous" clock sync, there should be no gpu events (i.e. the function early-outs
1854     // above).
1855     ASSERT(mGpuClockSync.gpuTimestampS != std::numeric_limits<double>::max() &&
1856            mGpuClockSync.cpuTimestampS != std::numeric_limits<double>::max());
1857 
1858     gpuSyncDriftSlope =
1859         (nextGpuSyncDiffS - lastGpuSyncDiffS) / (nextGpuSyncTimeS - lastGpuSyncTimeS);
1860 
1861     for (const GpuEvent &gpuEvent : mGpuEvents)
1862     {
1863         double gpuTimestampS =
1864             (gpuEvent.gpuTimestampCycles - mGpuEventTimestampOrigin) *
1865             static_cast<double>(
1866                 getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod) *
1867             1e-9;
1868 
1869         // Account for clock drift.
1870         gpuTimestampS += lastGpuSyncDiffS + gpuSyncDriftSlope * (gpuTimestampS - lastGpuSyncTimeS);
1871 
1872         // Generate the trace now that the GPU timestamp is available and clock drifts are
1873         // accounted for.
1874         static long long eventId = 1;
1875         static const unsigned char *categoryEnabled =
1876             TRACE_EVENT_API_GET_CATEGORY_ENABLED(platform, "gpu.angle.gpu");
1877         platform->addTraceEvent(platform, gpuEvent.phase, categoryEnabled, gpuEvent.name.data(),
1878                                 eventId++, gpuTimestampS, 0, nullptr, nullptr, nullptr,
1879                                 TRACE_EVENT_FLAG_NONE);
1880     }
1881 
1882     mGpuEvents.clear();
1883 }
1884 
clearAllGarbage()1885 void ContextVk::clearAllGarbage()
1886 {
1887     for (vk::GarbageObject &garbage : mCurrentGarbage)
1888     {
1889         garbage.destroy(mRenderer);
1890     }
1891     mCurrentGarbage.clear();
1892     mCommandQueue.clearAllGarbage(mRenderer);
1893 }
1894 
handleDeviceLost()1895 void ContextVk::handleDeviceLost()
1896 {
1897     mOutsideRenderPassCommands.reset();
1898     mRenderPassCommands.reset();
1899 
1900     mCommandQueue.handleDeviceLost(mRenderer);
1901     clearAllGarbage();
1902 
1903     mRenderer->notifyDeviceLost();
1904 }
1905 
drawArrays(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count)1906 angle::Result ContextVk::drawArrays(const gl::Context *context,
1907                                     gl::PrimitiveMode mode,
1908                                     GLint first,
1909                                     GLsizei count)
1910 {
1911     vk::CommandBuffer *commandBuffer = nullptr;
1912     uint32_t clampedVertexCount      = gl::GetClampedVertexCount<uint32_t>(count);
1913 
1914     if (mode == gl::PrimitiveMode::LineLoop)
1915     {
1916         uint32_t numIndices;
1917         ANGLE_TRY(setupLineLoopDraw(context, mode, first, count, gl::DrawElementsType::InvalidEnum,
1918                                     nullptr, &commandBuffer, &numIndices));
1919         vk::LineLoopHelper::Draw(numIndices, 0, commandBuffer);
1920     }
1921     else
1922     {
1923         ANGLE_TRY(setupDraw(context, mode, first, count, 1, gl::DrawElementsType::InvalidEnum,
1924                             nullptr, mNonIndexedDirtyBitsMask, &commandBuffer));
1925         commandBuffer->draw(clampedVertexCount, first);
1926     }
1927 
1928     return angle::Result::Continue;
1929 }
1930 
drawArraysInstanced(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instances)1931 angle::Result ContextVk::drawArraysInstanced(const gl::Context *context,
1932                                              gl::PrimitiveMode mode,
1933                                              GLint first,
1934                                              GLsizei count,
1935                                              GLsizei instances)
1936 {
1937     vk::CommandBuffer *commandBuffer = nullptr;
1938 
1939     if (mode == gl::PrimitiveMode::LineLoop)
1940     {
1941         uint32_t clampedVertexCount = gl::GetClampedVertexCount<uint32_t>(count);
1942         uint32_t numIndices;
1943         ANGLE_TRY(setupLineLoopDraw(context, mode, first, clampedVertexCount,
1944                                     gl::DrawElementsType::InvalidEnum, nullptr, &commandBuffer,
1945                                     &numIndices));
1946         commandBuffer->drawIndexedInstanced(numIndices, instances);
1947         return angle::Result::Continue;
1948     }
1949 
1950     ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum,
1951                         nullptr, mNonIndexedDirtyBitsMask, &commandBuffer));
1952     commandBuffer->drawInstanced(gl::GetClampedVertexCount<uint32_t>(count), instances, first);
1953     return angle::Result::Continue;
1954 }
1955 
drawArraysInstancedBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instances,GLuint baseInstance)1956 angle::Result ContextVk::drawArraysInstancedBaseInstance(const gl::Context *context,
1957                                                          gl::PrimitiveMode mode,
1958                                                          GLint first,
1959                                                          GLsizei count,
1960                                                          GLsizei instances,
1961                                                          GLuint baseInstance)
1962 {
1963     vk::CommandBuffer *commandBuffer = nullptr;
1964 
1965     if (mode == gl::PrimitiveMode::LineLoop)
1966     {
1967         uint32_t clampedVertexCount = gl::GetClampedVertexCount<uint32_t>(count);
1968         uint32_t numIndices;
1969         ANGLE_TRY(setupLineLoopDraw(context, mode, first, clampedVertexCount,
1970                                     gl::DrawElementsType::InvalidEnum, nullptr, &commandBuffer,
1971                                     &numIndices));
1972         commandBuffer->drawIndexedInstancedBaseVertexBaseInstance(numIndices, instances, 0, 0,
1973                                                                   baseInstance);
1974         return angle::Result::Continue;
1975     }
1976 
1977     ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum,
1978                         nullptr, mNonIndexedDirtyBitsMask, &commandBuffer));
1979     commandBuffer->drawInstancedBaseInstance(gl::GetClampedVertexCount<uint32_t>(count), instances,
1980                                              first, baseInstance);
1981     return angle::Result::Continue;
1982 }
1983 
drawElements(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices)1984 angle::Result ContextVk::drawElements(const gl::Context *context,
1985                                       gl::PrimitiveMode mode,
1986                                       GLsizei count,
1987                                       gl::DrawElementsType type,
1988                                       const void *indices)
1989 {
1990     vk::CommandBuffer *commandBuffer = nullptr;
1991     if (mode == gl::PrimitiveMode::LineLoop)
1992     {
1993         uint32_t indexCount;
1994         ANGLE_TRY(
1995             setupLineLoopDraw(context, mode, 0, count, type, indices, &commandBuffer, &indexCount));
1996         vk::LineLoopHelper::Draw(indexCount, 0, commandBuffer);
1997     }
1998     else
1999     {
2000         ANGLE_TRY(setupIndexedDraw(context, mode, count, 1, type, indices, &commandBuffer));
2001         commandBuffer->drawIndexed(count);
2002     }
2003 
2004     return angle::Result::Continue;
2005 }
2006 
drawElementsBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLint baseVertex)2007 angle::Result ContextVk::drawElementsBaseVertex(const gl::Context *context,
2008                                                 gl::PrimitiveMode mode,
2009                                                 GLsizei count,
2010                                                 gl::DrawElementsType type,
2011                                                 const void *indices,
2012                                                 GLint baseVertex)
2013 {
2014     vk::CommandBuffer *commandBuffer = nullptr;
2015     if (mode == gl::PrimitiveMode::LineLoop)
2016     {
2017         uint32_t indexCount;
2018         ANGLE_TRY(
2019             setupLineLoopDraw(context, mode, 0, count, type, indices, &commandBuffer, &indexCount));
2020         vk::LineLoopHelper::Draw(indexCount, baseVertex, commandBuffer);
2021     }
2022     else
2023     {
2024         ANGLE_TRY(setupIndexedDraw(context, mode, count, 1, type, indices, &commandBuffer));
2025         commandBuffer->drawIndexedBaseVertex(count, baseVertex);
2026     }
2027 
2028     return angle::Result::Continue;
2029 }
2030 
drawElementsInstanced(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances)2031 angle::Result ContextVk::drawElementsInstanced(const gl::Context *context,
2032                                                gl::PrimitiveMode mode,
2033                                                GLsizei count,
2034                                                gl::DrawElementsType type,
2035                                                const void *indices,
2036                                                GLsizei instances)
2037 {
2038     vk::CommandBuffer *commandBuffer = nullptr;
2039 
2040     if (mode == gl::PrimitiveMode::LineLoop)
2041     {
2042         uint32_t indexCount;
2043         ANGLE_TRY(
2044             setupLineLoopDraw(context, mode, 0, count, type, indices, &commandBuffer, &indexCount));
2045         count = indexCount;
2046     }
2047     else
2048     {
2049         ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices, &commandBuffer));
2050     }
2051 
2052     commandBuffer->drawIndexedInstanced(count, instances);
2053     return angle::Result::Continue;
2054 }
2055 
drawElementsInstancedBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances,GLint baseVertex)2056 angle::Result ContextVk::drawElementsInstancedBaseVertex(const gl::Context *context,
2057                                                          gl::PrimitiveMode mode,
2058                                                          GLsizei count,
2059                                                          gl::DrawElementsType type,
2060                                                          const void *indices,
2061                                                          GLsizei instances,
2062                                                          GLint baseVertex)
2063 {
2064     vk::CommandBuffer *commandBuffer = nullptr;
2065 
2066     if (mode == gl::PrimitiveMode::LineLoop)
2067     {
2068         uint32_t indexCount;
2069         ANGLE_TRY(
2070             setupLineLoopDraw(context, mode, 0, count, type, indices, &commandBuffer, &indexCount));
2071         count = indexCount;
2072     }
2073     else
2074     {
2075         ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices, &commandBuffer));
2076     }
2077 
2078     commandBuffer->drawIndexedInstancedBaseVertex(count, instances, baseVertex);
2079     return angle::Result::Continue;
2080 }
2081 
drawElementsInstancedBaseVertexBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances,GLint baseVertex,GLuint baseInstance)2082 angle::Result ContextVk::drawElementsInstancedBaseVertexBaseInstance(const gl::Context *context,
2083                                                                      gl::PrimitiveMode mode,
2084                                                                      GLsizei count,
2085                                                                      gl::DrawElementsType type,
2086                                                                      const void *indices,
2087                                                                      GLsizei instances,
2088                                                                      GLint baseVertex,
2089                                                                      GLuint baseInstance)
2090 {
2091     vk::CommandBuffer *commandBuffer = nullptr;
2092 
2093     if (mode == gl::PrimitiveMode::LineLoop)
2094     {
2095         uint32_t indexCount;
2096         ANGLE_TRY(
2097             setupLineLoopDraw(context, mode, 0, count, type, indices, &commandBuffer, &indexCount));
2098         commandBuffer->drawIndexedInstancedBaseVertexBaseInstance(indexCount, instances, 0,
2099                                                                   baseVertex, baseInstance);
2100         return angle::Result::Continue;
2101     }
2102 
2103     ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices, &commandBuffer));
2104     commandBuffer->drawIndexedInstancedBaseVertexBaseInstance(count, instances, 0, baseVertex,
2105                                                               baseInstance);
2106     return angle::Result::Continue;
2107 }
2108 
drawRangeElements(const gl::Context * context,gl::PrimitiveMode mode,GLuint start,GLuint end,GLsizei count,gl::DrawElementsType type,const void * indices)2109 angle::Result ContextVk::drawRangeElements(const gl::Context *context,
2110                                            gl::PrimitiveMode mode,
2111                                            GLuint start,
2112                                            GLuint end,
2113                                            GLsizei count,
2114                                            gl::DrawElementsType type,
2115                                            const void *indices)
2116 {
2117     return drawElements(context, mode, count, type, indices);
2118 }
2119 
drawRangeElementsBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLuint start,GLuint end,GLsizei count,gl::DrawElementsType type,const void * indices,GLint baseVertex)2120 angle::Result ContextVk::drawRangeElementsBaseVertex(const gl::Context *context,
2121                                                      gl::PrimitiveMode mode,
2122                                                      GLuint start,
2123                                                      GLuint end,
2124                                                      GLsizei count,
2125                                                      gl::DrawElementsType type,
2126                                                      const void *indices,
2127                                                      GLint baseVertex)
2128 {
2129     return drawElementsBaseVertex(context, mode, count, type, indices, baseVertex);
2130 }
2131 
getDevice() const2132 VkDevice ContextVk::getDevice() const
2133 {
2134     return mRenderer->getDevice();
2135 }
2136 
drawArraysIndirect(const gl::Context * context,gl::PrimitiveMode mode,const void * indirect)2137 angle::Result ContextVk::drawArraysIndirect(const gl::Context *context,
2138                                             gl::PrimitiveMode mode,
2139                                             const void *indirect)
2140 {
2141     gl::Buffer *indirectBuffer            = mState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
2142     vk::BufferHelper *currentIndirectBuf  = &vk::GetImpl(indirectBuffer)->getBuffer();
2143     VkDeviceSize currentIndirectBufOffset = reinterpret_cast<VkDeviceSize>(indirect);
2144 
2145     if (mVertexArray->getStreamingVertexAttribsMask().any())
2146     {
2147         mRenderPassCommands.bufferRead(&mResourceUseList, VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
2148                                        currentIndirectBuf);
2149 
2150         // We have instanced vertex attributes that need to be emulated for Vulkan.
2151         // invalidate any cache and map the buffer so that we can read the indirect data.
2152         // Mapping the buffer will cause a flush.
2153         ANGLE_TRY(currentIndirectBuf->invalidate(mRenderer, 0, sizeof(VkDrawIndirectCommand)));
2154         uint8_t *buffPtr;
2155         ANGLE_TRY(currentIndirectBuf->map(this, &buffPtr));
2156         const VkDrawIndirectCommand *indirectData =
2157             reinterpret_cast<VkDrawIndirectCommand *>(buffPtr + currentIndirectBufOffset);
2158 
2159         ANGLE_TRY(drawArraysInstanced(context, mode, indirectData->firstVertex,
2160                                       indirectData->vertexCount, indirectData->instanceCount));
2161 
2162         currentIndirectBuf->unmap(mRenderer);
2163         return angle::Result::Continue;
2164     }
2165 
2166     vk::CommandBuffer *commandBuffer = nullptr;
2167 
2168     if (mode == gl::PrimitiveMode::LineLoop)
2169     {
2170         ASSERT(indirectBuffer);
2171         vk::BufferHelper *dstIndirectBuf  = nullptr;
2172         VkDeviceSize dstIndirectBufOffset = 0;
2173 
2174         ANGLE_TRY(setupLineLoopIndirectDraw(context, mode, currentIndirectBuf,
2175                                             currentIndirectBufOffset, &commandBuffer,
2176                                             &dstIndirectBuf, &dstIndirectBufOffset));
2177 
2178         commandBuffer->drawIndexedIndirect(dstIndirectBuf->getBuffer(), dstIndirectBufOffset, 1, 0);
2179         return angle::Result::Continue;
2180     }
2181 
2182     ANGLE_TRY(setupIndirectDraw(context, mode, mNonIndexedDirtyBitsMask, currentIndirectBuf,
2183                                 currentIndirectBufOffset, &commandBuffer));
2184 
2185     commandBuffer->drawIndirect(currentIndirectBuf->getBuffer(), currentIndirectBufOffset, 1, 0);
2186     return angle::Result::Continue;
2187 }
2188 
drawElementsIndirect(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType type,const void * indirect)2189 angle::Result ContextVk::drawElementsIndirect(const gl::Context *context,
2190                                               gl::PrimitiveMode mode,
2191                                               gl::DrawElementsType type,
2192                                               const void *indirect)
2193 {
2194     VkDeviceSize currentIndirectBufOffset = reinterpret_cast<VkDeviceSize>(indirect);
2195     gl::Buffer *indirectBuffer            = mState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
2196     ASSERT(indirectBuffer);
2197     vk::BufferHelper *currentIndirectBuf = &vk::GetImpl(indirectBuffer)->getBuffer();
2198 
2199     if (mVertexArray->getStreamingVertexAttribsMask().any())
2200     {
2201         mRenderPassCommands.bufferRead(&mResourceUseList, VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
2202                                        currentIndirectBuf);
2203 
2204         // We have instanced vertex attributes that need to be emulated for Vulkan.
2205         // invalidate any cache and map the buffer so that we can read the indirect data.
2206         // Mapping the buffer will cause a flush.
2207         ANGLE_TRY(
2208             currentIndirectBuf->invalidate(mRenderer, 0, sizeof(VkDrawIndexedIndirectCommand)));
2209         uint8_t *buffPtr;
2210         ANGLE_TRY(currentIndirectBuf->map(this, &buffPtr));
2211         const VkDrawIndexedIndirectCommand *indirectData =
2212             reinterpret_cast<VkDrawIndexedIndirectCommand *>(buffPtr + currentIndirectBufOffset);
2213 
2214         ANGLE_TRY(drawElementsInstanced(context, mode, indirectData->indexCount, type, nullptr,
2215                                         indirectData->instanceCount));
2216 
2217         currentIndirectBuf->unmap(mRenderer);
2218         return angle::Result::Continue;
2219     }
2220 
2221     if (shouldConvertUint8VkIndexType(type) && mGraphicsDirtyBits[DIRTY_BIT_INDEX_BUFFER])
2222     {
2223         vk::BufferHelper *dstIndirectBuf;
2224         VkDeviceSize dstIndirectBufOffset;
2225 
2226         ANGLE_TRY(mVertexArray->convertIndexBufferIndirectGPU(
2227             this, currentIndirectBuf, currentIndirectBufOffset, &dstIndirectBuf,
2228             &dstIndirectBufOffset));
2229 
2230         currentIndirectBuf       = dstIndirectBuf;
2231         currentIndirectBufOffset = dstIndirectBufOffset;
2232     }
2233 
2234     vk::CommandBuffer *commandBuffer = nullptr;
2235 
2236     if (mode == gl::PrimitiveMode::LineLoop)
2237     {
2238         vk::BufferHelper *dstIndirectBuf;
2239         VkDeviceSize dstIndirectBufOffset;
2240 
2241         ANGLE_TRY(setupLineLoopIndexedIndirectDraw(context, mode, type, currentIndirectBuf,
2242                                                    currentIndirectBufOffset, &commandBuffer,
2243                                                    &dstIndirectBuf, &dstIndirectBufOffset));
2244 
2245         currentIndirectBuf       = dstIndirectBuf;
2246         currentIndirectBufOffset = dstIndirectBufOffset;
2247     }
2248     else
2249     {
2250         ANGLE_TRY(setupIndexedIndirectDraw(context, mode, type, currentIndirectBuf,
2251                                            currentIndirectBufOffset, &commandBuffer));
2252     }
2253 
2254     commandBuffer->drawIndexedIndirect(currentIndirectBuf->getBuffer(), currentIndirectBufOffset, 1,
2255                                        0);
2256     return angle::Result::Continue;
2257 }
2258 
clearWithRenderPassOp(const gl::Rectangle & clearArea,gl::DrawBufferMask clearColorBuffers,bool clearDepth,bool clearStencil,const VkClearColorValue & clearColorValue,const VkClearDepthStencilValue & clearDepthStencilValue)2259 angle::Result ContextVk::clearWithRenderPassOp(
2260     const gl::Rectangle &clearArea,
2261     gl::DrawBufferMask clearColorBuffers,
2262     bool clearDepth,
2263     bool clearStencil,
2264     const VkClearColorValue &clearColorValue,
2265     const VkClearDepthStencilValue &clearDepthStencilValue)
2266 {
2267     // Validate cache variable is in sync.
2268     ASSERT(mDrawFramebuffer == vk::GetImpl(mState.getDrawFramebuffer()));
2269 
2270     // Start a new render pass if:
2271     //
2272     // - no render pass has started,
2273     // - there is a render pass started but it contains commands; we cannot modify its ops, so new
2274     // render pass is needed,
2275     // - the current render area doesn't match the clear area.  We need the render area to be
2276     // exactly as specified by the scissor for the loadOp to clear only that area.  See
2277     // ContextVk::updateScissor for more information.
2278     if (!mRenderPassCommands.started() ||
2279         (mRenderPassCommands.started() && !mRenderPassCommands.empty()) ||
2280         mRenderPassCommands.getRenderArea() != clearArea)
2281     {
2282         ANGLE_TRY(startRenderPass(clearArea));
2283     }
2284     else
2285     {
2286         flushOutsideRenderPassCommands();
2287     }
2288 
2289     size_t attachmentIndexVk = 0;
2290 
2291     // Go through clearColorBuffers and set the appropriate loadOp and clear values.
2292     for (size_t colorIndexGL : mDrawFramebuffer->getState().getEnabledDrawBuffers())
2293     {
2294         if (clearColorBuffers.test(colorIndexGL))
2295         {
2296             RenderTargetVk *renderTarget = mDrawFramebuffer->getColorDrawRenderTarget(colorIndexGL);
2297 
2298             // If the render target doesn't have alpha, but its emulated format has it, clear the
2299             // alpha to 1.
2300             VkClearColorValue value = clearColorValue;
2301             if (mDrawFramebuffer->getEmulatedAlphaAttachmentMask()[colorIndexGL])
2302             {
2303                 const vk::Format &format = renderTarget->getImageFormat();
2304                 if (format.vkFormatIsInt)
2305                 {
2306                     if (format.vkFormatIsUnsigned)
2307                     {
2308                         value.uint32[3] = kEmulatedAlphaValue;
2309                     }
2310                     else
2311                     {
2312                         value.int32[3] = kEmulatedAlphaValue;
2313                     }
2314                 }
2315                 else
2316                 {
2317                     value.float32[3] = kEmulatedAlphaValue;
2318                 }
2319             }
2320 
2321             mRenderPassCommands.clearRenderPassColorAttachment(attachmentIndexVk, value);
2322         }
2323         ++attachmentIndexVk;
2324     }
2325 
2326     // Set the appropriate loadOp and clear values for depth and stencil.
2327     RenderTargetVk *depthStencilRenderTarget = mDrawFramebuffer->getDepthStencilRenderTarget();
2328     if (depthStencilRenderTarget)
2329     {
2330         const vk::Format &format = depthStencilRenderTarget->getImageFormat();
2331         if (format.hasEmulatedImageChannels())
2332         {
2333             if (format.intendedFormat().stencilBits == 0)
2334             {
2335                 // If the format we picked has stencil but user did not ask for
2336                 // it due to hardware limitation, force clear the stencil so
2337                 // that no load will happen. Also don't try to store stencil
2338                 // value as well. Same logic for depth bits bellow.
2339                 mRenderPassCommands.invalidateRenderPassStencilAttachment(attachmentIndexVk);
2340                 clearStencil = true;
2341             }
2342             if (format.intendedFormat().depthBits == 0)
2343             {
2344                 mRenderPassCommands.invalidateRenderPassDepthAttachment(attachmentIndexVk);
2345                 clearDepth = true;
2346             }
2347         }
2348 
2349         if (clearDepth)
2350         {
2351             mRenderPassCommands.clearRenderPassDepthAttachment(attachmentIndexVk,
2352                                                                clearDepthStencilValue.depth);
2353         }
2354 
2355         if (clearStencil)
2356         {
2357             mRenderPassCommands.clearRenderPassStencilAttachment(attachmentIndexVk,
2358                                                                  clearDepthStencilValue.stencil);
2359         }
2360     }
2361 
2362     return angle::Result::Continue;
2363 }
2364 
optimizeRenderPassForPresent(VkFramebuffer framebufferHandle)2365 void ContextVk::optimizeRenderPassForPresent(VkFramebuffer framebufferHandle)
2366 {
2367     if (!mRenderPassCommands.started())
2368     {
2369         return;
2370     }
2371 
2372     if (framebufferHandle != mRenderPassCommands.getFramebufferHandle())
2373     {
2374         return;
2375     }
2376 
2377     RenderTargetVk *color0RenderTarget = mDrawFramebuffer->getColorDrawRenderTarget(0);
2378     if (!color0RenderTarget)
2379     {
2380         return;
2381     }
2382 
2383     // EGL1.5 spec: The contents of ancillary buffers are always undefined after calling
2384     // eglSwapBuffers
2385     RenderTargetVk *depthStencilRenderTarget = mDrawFramebuffer->getDepthStencilRenderTarget();
2386     if (depthStencilRenderTarget)
2387     {
2388         size_t depthStencilAttachmentIndexVk = mDrawFramebuffer->getDepthStencilAttachmentIndexVk();
2389         // Change depthstencil attachment storeOp to DONT_CARE
2390         mRenderPassCommands.invalidateRenderPassStencilAttachment(depthStencilAttachmentIndexVk);
2391         mRenderPassCommands.invalidateRenderPassDepthAttachment(depthStencilAttachmentIndexVk);
2392         // Mark content as invalid so that we will not load them in next renderpass
2393         depthStencilRenderTarget->invalidateContent();
2394     }
2395 
2396     // Use finalLayout instead of extra barrier for layout change to present
2397     vk::ImageHelper &image = color0RenderTarget->getImage();
2398     image.setCurrentImageLayout(vk::ImageLayout::Present);
2399     mRenderPassCommands.updateRenderPassAttachmentFinalLayout(0, image.getCurrentImageLayout());
2400 }
2401 
getResetStatus()2402 gl::GraphicsResetStatus ContextVk::getResetStatus()
2403 {
2404     if (mRenderer->isDeviceLost())
2405     {
2406         // TODO(geofflang): It may be possible to track which context caused the device lost and
2407         // return either GL_GUILTY_CONTEXT_RESET or GL_INNOCENT_CONTEXT_RESET.
2408         // http://anglebug.com/2787
2409         return gl::GraphicsResetStatus::UnknownContextReset;
2410     }
2411 
2412     return gl::GraphicsResetStatus::NoError;
2413 }
2414 
getVendorString() const2415 std::string ContextVk::getVendorString() const
2416 {
2417     UNIMPLEMENTED();
2418     return std::string();
2419 }
2420 
getRendererDescription() const2421 std::string ContextVk::getRendererDescription() const
2422 {
2423     return mRenderer->getRendererDescription();
2424 }
2425 
insertEventMarker(GLsizei length,const char * marker)2426 angle::Result ContextVk::insertEventMarker(GLsizei length, const char *marker)
2427 {
2428     if (!mRenderer->enableDebugUtils())
2429         return angle::Result::Continue;
2430 
2431     vk::PrimaryCommandBuffer *primary;
2432     ANGLE_TRY(flushAndGetPrimaryCommandBuffer(&primary));
2433 
2434     VkDebugUtilsLabelEXT label;
2435     vk::MakeDebugUtilsLabel(GL_DEBUG_SOURCE_APPLICATION, marker, &label);
2436     primary->insertDebugUtilsLabelEXT(label);
2437 
2438     return angle::Result::Continue;
2439 }
2440 
pushGroupMarker(GLsizei length,const char * marker)2441 angle::Result ContextVk::pushGroupMarker(GLsizei length, const char *marker)
2442 {
2443     if (!mRenderer->enableDebugUtils())
2444         return angle::Result::Continue;
2445 
2446     vk::PrimaryCommandBuffer *primary;
2447     ANGLE_TRY(flushAndGetPrimaryCommandBuffer(&primary));
2448 
2449     VkDebugUtilsLabelEXT label;
2450     vk::MakeDebugUtilsLabel(GL_DEBUG_SOURCE_APPLICATION, marker, &label);
2451     primary->beginDebugUtilsLabelEXT(label);
2452 
2453     return angle::Result::Continue;
2454 }
2455 
popGroupMarker()2456 angle::Result ContextVk::popGroupMarker()
2457 {
2458     if (!mRenderer->enableDebugUtils())
2459         return angle::Result::Continue;
2460 
2461     vk::PrimaryCommandBuffer *primary;
2462     ANGLE_TRY(flushAndGetPrimaryCommandBuffer(&primary));
2463     primary->endDebugUtilsLabelEXT();
2464 
2465     return angle::Result::Continue;
2466 }
2467 
pushDebugGroup(const gl::Context * context,GLenum source,GLuint id,const std::string & message)2468 angle::Result ContextVk::pushDebugGroup(const gl::Context *context,
2469                                         GLenum source,
2470                                         GLuint id,
2471                                         const std::string &message)
2472 {
2473     if (!mRenderer->enableDebugUtils())
2474         return angle::Result::Continue;
2475 
2476     vk::PrimaryCommandBuffer *primary;
2477     ANGLE_TRY(flushAndGetPrimaryCommandBuffer(&primary));
2478 
2479     VkDebugUtilsLabelEXT label;
2480     vk::MakeDebugUtilsLabel(source, message.c_str(), &label);
2481     primary->insertDebugUtilsLabelEXT(label);
2482 
2483     return angle::Result::Continue;
2484 }
2485 
popDebugGroup(const gl::Context * context)2486 angle::Result ContextVk::popDebugGroup(const gl::Context *context)
2487 {
2488     if (!mRenderer->enableDebugUtils())
2489         return angle::Result::Continue;
2490 
2491     vk::PrimaryCommandBuffer *primary;
2492     ANGLE_TRY(flushAndGetPrimaryCommandBuffer(&primary));
2493     primary->endDebugUtilsLabelEXT();
2494 
2495     return angle::Result::Continue;
2496 }
2497 
isViewportFlipEnabledForDrawFBO() const2498 bool ContextVk::isViewportFlipEnabledForDrawFBO() const
2499 {
2500     return mFlipViewportForDrawFramebuffer && mFlipYForCurrentSurface;
2501 }
2502 
isViewportFlipEnabledForReadFBO() const2503 bool ContextVk::isViewportFlipEnabledForReadFBO() const
2504 {
2505     return mFlipViewportForReadFramebuffer;
2506 }
2507 
isRotatedAspectRatioForDrawFBO() const2508 bool ContextVk::isRotatedAspectRatioForDrawFBO() const
2509 {
2510     return IsRotatedAspectRatio(mCurrentRotationDrawFramebuffer);
2511 }
isRotatedAspectRatioForReadFBO() const2512 bool ContextVk::isRotatedAspectRatioForReadFBO() const
2513 {
2514     return IsRotatedAspectRatio(mCurrentRotationReadFramebuffer);
2515 }
2516 
updateColorMask(const gl::BlendState & blendState)2517 void ContextVk::updateColorMask(const gl::BlendState &blendState)
2518 {
2519     mClearColorMask =
2520         gl_vk::GetColorComponentFlags(blendState.colorMaskRed, blendState.colorMaskGreen,
2521                                       blendState.colorMaskBlue, blendState.colorMaskAlpha);
2522 
2523     FramebufferVk *framebufferVk = vk::GetImpl(mState.getDrawFramebuffer());
2524     mGraphicsPipelineDesc->updateColorWriteMask(&mGraphicsPipelineTransition, mClearColorMask,
2525                                                 framebufferVk->getEmulatedAlphaAttachmentMask());
2526 }
2527 
updateSampleMask(const gl::State & glState)2528 void ContextVk::updateSampleMask(const gl::State &glState)
2529 {
2530     // If sample coverage is enabled, emulate it by generating and applying a mask on top of the
2531     // sample mask.
2532     uint32_t coverageSampleCount = GetCoverageSampleCount(glState, mDrawFramebuffer);
2533 
2534     static_assert(sizeof(uint32_t) == sizeof(GLbitfield), "Vulkan assumes 32-bit sample masks");
2535     for (uint32_t maskNumber = 0; maskNumber < glState.getMaxSampleMaskWords(); ++maskNumber)
2536     {
2537         uint32_t mask = glState.isSampleMaskEnabled() ? glState.getSampleMaskWord(maskNumber)
2538                                                       : std::numeric_limits<uint32_t>::max();
2539 
2540         ApplySampleCoverage(glState, coverageSampleCount, maskNumber, &mask);
2541 
2542         mGraphicsPipelineDesc->updateSampleMask(&mGraphicsPipelineTransition, maskNumber, mask);
2543     }
2544 }
2545 
updateViewport(FramebufferVk * framebufferVk,const gl::Rectangle & viewport,float nearPlane,float farPlane,bool invertViewport)2546 void ContextVk::updateViewport(FramebufferVk *framebufferVk,
2547                                const gl::Rectangle &viewport,
2548                                float nearPlane,
2549                                float farPlane,
2550                                bool invertViewport)
2551 {
2552     VkViewport vkViewport;
2553     const gl::Caps &caps                   = getCaps();
2554     const VkPhysicalDeviceLimits &limitsVk = mRenderer->getPhysicalDeviceProperties().limits;
2555     const int viewportBoundsRangeLow       = static_cast<int>(limitsVk.viewportBoundsRange[0]);
2556     const int viewportBoundsRangeHigh      = static_cast<int>(limitsVk.viewportBoundsRange[1]);
2557 
2558     // Clamp the viewport values to what Vulkan specifies
2559 
2560     // width must be greater than 0.0 and less than or equal to
2561     // VkPhysicalDeviceLimits::maxViewportDimensions[0]
2562     int correctedWidth = std::min<int>(viewport.width, caps.maxViewportWidth);
2563     correctedWidth     = std::max<int>(correctedWidth, 0);
2564     // height must be greater than 0.0 and less than or equal to
2565     // VkPhysicalDeviceLimits::maxViewportDimensions[1]
2566     int correctedHeight = std::min<int>(viewport.height, caps.maxViewportHeight);
2567     correctedHeight     = std::max<int>(correctedHeight, 0);
2568     // x and y must each be between viewportBoundsRange[0] and viewportBoundsRange[1], inclusive
2569     int correctedX = std::min<int>(viewport.x, viewportBoundsRangeHigh);
2570     correctedX     = std::max<int>(correctedX, viewportBoundsRangeLow);
2571     int correctedY = std::min<int>(viewport.y, viewportBoundsRangeHigh);
2572     correctedY     = std::max<int>(correctedY, viewportBoundsRangeLow);
2573     // x + width must be less than or equal to viewportBoundsRange[1]
2574     if ((correctedX + correctedWidth) > viewportBoundsRangeHigh)
2575     {
2576         correctedWidth = viewportBoundsRangeHigh - correctedX;
2577     }
2578     // y + height must be less than or equal to viewportBoundsRange[1]
2579     if ((correctedY + correctedHeight) > viewportBoundsRangeHigh)
2580     {
2581         correctedHeight = viewportBoundsRangeHigh - correctedY;
2582     }
2583 
2584     gl::Box framebufferDimensions = framebufferVk->getState().getDimensions();
2585     if (isRotatedAspectRatioForDrawFBO())
2586     {
2587         // The surface is rotated 90/270 degrees.  This changes the aspect ratio of the surface.
2588         // Swap the width and height of the viewport we calculate, and the framebuffer height that
2589         // we use to calculate it with.
2590         // TODO(ianelliott): handle small viewport/scissor cases.  http://anglebug.com/4431
2591         std::swap(correctedWidth, correctedHeight);
2592         std::swap(framebufferDimensions.width, framebufferDimensions.height);
2593     }
2594     gl::Rectangle correctedRect =
2595         gl::Rectangle(correctedX, correctedY, correctedWidth, correctedHeight);
2596 
2597     gl_vk::GetViewport(correctedRect, nearPlane, farPlane, invertViewport,
2598                        framebufferDimensions.height, &vkViewport);
2599     mGraphicsPipelineDesc->updateViewport(&mGraphicsPipelineTransition, vkViewport);
2600     invalidateGraphicsDriverUniforms();
2601 }
2602 
updateDepthRange(float nearPlane,float farPlane)2603 void ContextVk::updateDepthRange(float nearPlane, float farPlane)
2604 {
2605     invalidateGraphicsDriverUniforms();
2606     mGraphicsPipelineDesc->updateDepthRange(&mGraphicsPipelineTransition, nearPlane, farPlane);
2607 }
2608 
updateScissor(const gl::State & glState)2609 angle::Result ContextVk::updateScissor(const gl::State &glState)
2610 {
2611     FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer());
2612     gl::Rectangle renderArea     = framebufferVk->getCompleteRenderArea();
2613 
2614     // Clip the render area to the viewport.
2615     gl::Rectangle viewportClippedRenderArea;
2616     gl::ClipRectangle(renderArea, glState.getViewport(), &viewportClippedRenderArea);
2617 
2618     gl::Rectangle scissoredArea = ClipRectToScissor(getState(), viewportClippedRenderArea, false);
2619     if (isViewportFlipEnabledForDrawFBO())
2620     {
2621         scissoredArea.y = renderArea.height - scissoredArea.y - scissoredArea.height;
2622     }
2623     if (isRotatedAspectRatioForDrawFBO())
2624     {
2625         // The surface is rotated 90/270 degrees.  This changes the aspect ratio of the surface.
2626         // Swap the width and height of the scissor we use.
2627         // TODO(ianelliott): handle small viewport/scissor cases.  http://anglebug.com/4431
2628         std::swap(scissoredArea.width, scissoredArea.height);
2629     }
2630 
2631     mGraphicsPipelineDesc->updateScissor(&mGraphicsPipelineTransition,
2632                                          gl_vk::GetRect(scissoredArea));
2633 
2634     // If the scissor has grown beyond the previous scissoredRenderArea, make sure the render pass
2635     // is restarted.  Otherwise, we can continue using the same renderpass area.
2636     //
2637     // Without a scissor, the render pass area covers the whole of the framebuffer.  With a
2638     // scissored clear, the render pass area could be smaller than the framebuffer size.  When the
2639     // scissor changes, if the scissor area is completely encompassed by the render pass area, it's
2640     // possible to continue using the same render pass.  However, if the current render pass area
2641     // is too small, we need to start a new one.  The latter can happen if a scissored clear starts
2642     // a render pass, the scissor is disabled and a draw call is issued to affect the whole
2643     // framebuffer.
2644     gl::Rectangle scissoredRenderArea = framebufferVk->getScissoredRenderArea(this);
2645     if (!mRenderPassCommands.empty())
2646     {
2647         if (!mRenderPassCommands.getRenderArea().encloses(scissoredRenderArea))
2648         {
2649             ANGLE_TRY(endRenderPass());
2650         }
2651     }
2652 
2653     return angle::Result::Continue;
2654 }
2655 
invalidateProgramBindingHelper(const gl::State & glState)2656 void ContextVk::invalidateProgramBindingHelper(const gl::State &glState)
2657 {
2658     mExecutable = nullptr;
2659 
2660     if (glState.getProgram())
2661     {
2662         mProgram    = vk::GetImpl(glState.getProgram());
2663         mExecutable = &mProgram->getExecutable();
2664     }
2665     else
2666     {
2667         mProgram    = nullptr;
2668         mExecutable = nullptr;
2669     }
2670 
2671     if (glState.getProgramPipeline())
2672     {
2673         mProgramPipeline = vk::GetImpl(glState.getProgramPipeline());
2674         if (!mExecutable)
2675         {
2676             // A bound program always overrides a program pipeline
2677             mExecutable = &mProgramPipeline->getExecutable();
2678         }
2679     }
2680     else
2681     {
2682         mProgramPipeline = nullptr;
2683     }
2684 }
2685 
invalidateProgramExecutableHelper(const gl::Context * context)2686 angle::Result ContextVk::invalidateProgramExecutableHelper(const gl::Context *context)
2687 {
2688     const gl::State &glState = context->getState();
2689 
2690     if (glState.getProgramExecutable()->isCompute())
2691     {
2692         invalidateCurrentComputePipeline();
2693     }
2694     else
2695     {
2696         // No additional work is needed here. We will update the pipeline desc
2697         // later.
2698         invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask());
2699         invalidateVertexAndIndexBuffers();
2700         bool useVertexBuffer = (glState.getProgramExecutable()->getMaxActiveAttribLocation() > 0);
2701         mNonIndexedDirtyBitsMask.set(DIRTY_BIT_VERTEX_BUFFERS, useVertexBuffer);
2702         mIndexedDirtyBitsMask.set(DIRTY_BIT_VERTEX_BUFFERS, useVertexBuffer);
2703         mCurrentGraphicsPipeline = nullptr;
2704         mGraphicsPipelineTransition.reset();
2705     }
2706 
2707     return angle::Result::Continue;
2708 }
2709 
syncState(const gl::Context * context,const gl::State::DirtyBits & dirtyBits,const gl::State::DirtyBits & bitMask)2710 angle::Result ContextVk::syncState(const gl::Context *context,
2711                                    const gl::State::DirtyBits &dirtyBits,
2712                                    const gl::State::DirtyBits &bitMask)
2713 {
2714     const gl::State &glState                       = context->getState();
2715     const gl::ProgramExecutable *programExecutable = glState.getProgramExecutable();
2716 
2717     if ((dirtyBits & mPipelineDirtyBitsMask).any() &&
2718         (programExecutable == nullptr || !programExecutable->isCompute()))
2719     {
2720         invalidateCurrentGraphicsPipeline();
2721     }
2722 
2723     for (auto iter = dirtyBits.begin(), endIter = dirtyBits.end(); iter != endIter; ++iter)
2724     {
2725         size_t dirtyBit = *iter;
2726         switch (dirtyBit)
2727         {
2728             case gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED:
2729             case gl::State::DIRTY_BIT_SCISSOR:
2730                 ANGLE_TRY(updateScissor(glState));
2731                 break;
2732             case gl::State::DIRTY_BIT_VIEWPORT:
2733             {
2734                 FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer());
2735                 updateViewport(framebufferVk, glState.getViewport(), glState.getNearPlane(),
2736                                glState.getFarPlane(), isViewportFlipEnabledForDrawFBO());
2737                 // Update the scissor, which will be constrained to the viewport
2738                 ANGLE_TRY(updateScissor(glState));
2739                 break;
2740             }
2741             case gl::State::DIRTY_BIT_DEPTH_RANGE:
2742                 updateDepthRange(glState.getNearPlane(), glState.getFarPlane());
2743                 break;
2744             case gl::State::DIRTY_BIT_BLEND_ENABLED:
2745                 mGraphicsPipelineDesc->updateBlendEnabled(&mGraphicsPipelineTransition,
2746                                                           glState.isBlendEnabled());
2747                 break;
2748             case gl::State::DIRTY_BIT_BLEND_COLOR:
2749                 mGraphicsPipelineDesc->updateBlendColor(&mGraphicsPipelineTransition,
2750                                                         glState.getBlendColor());
2751                 break;
2752             case gl::State::DIRTY_BIT_BLEND_FUNCS:
2753                 mGraphicsPipelineDesc->updateBlendFuncs(&mGraphicsPipelineTransition,
2754                                                         glState.getBlendState());
2755                 break;
2756             case gl::State::DIRTY_BIT_BLEND_EQUATIONS:
2757                 mGraphicsPipelineDesc->updateBlendEquations(&mGraphicsPipelineTransition,
2758                                                             glState.getBlendState());
2759                 break;
2760             case gl::State::DIRTY_BIT_COLOR_MASK:
2761                 updateColorMask(glState.getBlendState());
2762                 break;
2763             case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
2764                 mGraphicsPipelineDesc->updateAlphaToCoverageEnable(
2765                     &mGraphicsPipelineTransition, glState.isSampleAlphaToCoverageEnabled());
2766                 ASSERT(gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE >
2767                        gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED);
2768                 iter.setLaterBit(gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE);
2769                 break;
2770             case gl::State::DIRTY_BIT_SAMPLE_COVERAGE_ENABLED:
2771                 updateSampleMask(glState);
2772                 break;
2773             case gl::State::DIRTY_BIT_SAMPLE_COVERAGE:
2774                 updateSampleMask(glState);
2775                 break;
2776             case gl::State::DIRTY_BIT_SAMPLE_MASK_ENABLED:
2777                 updateSampleMask(glState);
2778                 break;
2779             case gl::State::DIRTY_BIT_SAMPLE_MASK:
2780                 updateSampleMask(glState);
2781                 break;
2782             case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED:
2783                 mGraphicsPipelineDesc->updateDepthTestEnabled(&mGraphicsPipelineTransition,
2784                                                               glState.getDepthStencilState(),
2785                                                               glState.getDrawFramebuffer());
2786                 break;
2787             case gl::State::DIRTY_BIT_DEPTH_FUNC:
2788                 mGraphicsPipelineDesc->updateDepthFunc(&mGraphicsPipelineTransition,
2789                                                        glState.getDepthStencilState());
2790                 break;
2791             case gl::State::DIRTY_BIT_DEPTH_MASK:
2792                 mGraphicsPipelineDesc->updateDepthWriteEnabled(&mGraphicsPipelineTransition,
2793                                                                glState.getDepthStencilState(),
2794                                                                glState.getDrawFramebuffer());
2795                 break;
2796             case gl::State::DIRTY_BIT_STENCIL_TEST_ENABLED:
2797                 mGraphicsPipelineDesc->updateStencilTestEnabled(&mGraphicsPipelineTransition,
2798                                                                 glState.getDepthStencilState(),
2799                                                                 glState.getDrawFramebuffer());
2800                 break;
2801             case gl::State::DIRTY_BIT_STENCIL_FUNCS_FRONT:
2802                 mGraphicsPipelineDesc->updateStencilFrontFuncs(&mGraphicsPipelineTransition,
2803                                                                glState.getStencilRef(),
2804                                                                glState.getDepthStencilState());
2805                 break;
2806             case gl::State::DIRTY_BIT_STENCIL_FUNCS_BACK:
2807                 mGraphicsPipelineDesc->updateStencilBackFuncs(&mGraphicsPipelineTransition,
2808                                                               glState.getStencilBackRef(),
2809                                                               glState.getDepthStencilState());
2810                 break;
2811             case gl::State::DIRTY_BIT_STENCIL_OPS_FRONT:
2812                 mGraphicsPipelineDesc->updateStencilFrontOps(&mGraphicsPipelineTransition,
2813                                                              glState.getDepthStencilState());
2814                 break;
2815             case gl::State::DIRTY_BIT_STENCIL_OPS_BACK:
2816                 mGraphicsPipelineDesc->updateStencilBackOps(&mGraphicsPipelineTransition,
2817                                                             glState.getDepthStencilState());
2818                 break;
2819             case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT:
2820                 mGraphicsPipelineDesc->updateStencilFrontWriteMask(&mGraphicsPipelineTransition,
2821                                                                    glState.getDepthStencilState(),
2822                                                                    glState.getDrawFramebuffer());
2823                 break;
2824             case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK:
2825                 mGraphicsPipelineDesc->updateStencilBackWriteMask(&mGraphicsPipelineTransition,
2826                                                                   glState.getDepthStencilState(),
2827                                                                   glState.getDrawFramebuffer());
2828                 break;
2829             case gl::State::DIRTY_BIT_CULL_FACE_ENABLED:
2830             case gl::State::DIRTY_BIT_CULL_FACE:
2831                 mGraphicsPipelineDesc->updateCullMode(&mGraphicsPipelineTransition,
2832                                                       glState.getRasterizerState());
2833                 break;
2834             case gl::State::DIRTY_BIT_FRONT_FACE:
2835                 mGraphicsPipelineDesc->updateFrontFace(&mGraphicsPipelineTransition,
2836                                                        glState.getRasterizerState(),
2837                                                        isViewportFlipEnabledForDrawFBO());
2838                 break;
2839             case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED:
2840                 mGraphicsPipelineDesc->updatePolygonOffsetFillEnabled(
2841                     &mGraphicsPipelineTransition, glState.isPolygonOffsetFillEnabled());
2842                 break;
2843             case gl::State::DIRTY_BIT_POLYGON_OFFSET:
2844                 mGraphicsPipelineDesc->updatePolygonOffset(&mGraphicsPipelineTransition,
2845                                                            glState.getRasterizerState());
2846                 break;
2847             case gl::State::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED:
2848                 mGraphicsPipelineDesc->updateRasterizerDiscardEnabled(
2849                     &mGraphicsPipelineTransition, glState.isRasterizerDiscardEnabled());
2850                 break;
2851             case gl::State::DIRTY_BIT_LINE_WIDTH:
2852                 mGraphicsPipelineDesc->updateLineWidth(&mGraphicsPipelineTransition,
2853                                                        glState.getLineWidth());
2854                 break;
2855             case gl::State::DIRTY_BIT_PRIMITIVE_RESTART_ENABLED:
2856                 mGraphicsPipelineDesc->updatePrimitiveRestartEnabled(
2857                     &mGraphicsPipelineTransition, glState.isPrimitiveRestartEnabled());
2858                 break;
2859             case gl::State::DIRTY_BIT_CLEAR_COLOR:
2860                 mClearColorValue.color.float32[0] = glState.getColorClearValue().red;
2861                 mClearColorValue.color.float32[1] = glState.getColorClearValue().green;
2862                 mClearColorValue.color.float32[2] = glState.getColorClearValue().blue;
2863                 mClearColorValue.color.float32[3] = glState.getColorClearValue().alpha;
2864                 break;
2865             case gl::State::DIRTY_BIT_CLEAR_DEPTH:
2866                 mClearDepthStencilValue.depthStencil.depth = glState.getDepthClearValue();
2867                 break;
2868             case gl::State::DIRTY_BIT_CLEAR_STENCIL:
2869                 mClearDepthStencilValue.depthStencil.stencil =
2870                     static_cast<uint32_t>(glState.getStencilClearValue());
2871                 break;
2872             case gl::State::DIRTY_BIT_UNPACK_STATE:
2873                 // This is a no-op, it's only important to use the right unpack state when we do
2874                 // setImage or setSubImage in TextureVk, which is plumbed through the frontend
2875                 // call
2876                 break;
2877             case gl::State::DIRTY_BIT_UNPACK_BUFFER_BINDING:
2878                 break;
2879             case gl::State::DIRTY_BIT_PACK_STATE:
2880                 // This is a no-op, its only important to use the right pack state when we do
2881                 // call readPixels later on.
2882                 break;
2883             case gl::State::DIRTY_BIT_PACK_BUFFER_BINDING:
2884                 break;
2885             case gl::State::DIRTY_BIT_DITHER_ENABLED:
2886                 break;
2887             case gl::State::DIRTY_BIT_GENERATE_MIPMAP_HINT:
2888                 break;
2889             case gl::State::DIRTY_BIT_SHADER_DERIVATIVE_HINT:
2890                 break;
2891             case gl::State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING:
2892                 updateFlipViewportReadFramebuffer(context->getState());
2893                 updateSurfaceRotationReadFramebuffer(glState);
2894                 break;
2895             case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING:
2896             {
2897                 // FramebufferVk::syncState signals that we should start a new command buffer.
2898                 // But changing the binding can skip FramebufferVk::syncState if the Framebuffer
2899                 // has no dirty bits. Thus we need to explicitly clear the current command
2900                 // buffer to ensure we start a new one. Note that we always start a new command
2901                 // buffer because we currently can only support one open RenderPass at a time.
2902                 onRenderPassFinished();
2903 
2904                 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
2905                 mDrawFramebuffer                 = vk::GetImpl(drawFramebuffer);
2906                 updateFlipViewportDrawFramebuffer(glState);
2907                 updateSurfaceRotationDrawFramebuffer(glState);
2908                 updateViewport(mDrawFramebuffer, glState.getViewport(), glState.getNearPlane(),
2909                                glState.getFarPlane(), isViewportFlipEnabledForDrawFBO());
2910                 updateColorMask(glState.getBlendState());
2911                 updateSampleMask(glState);
2912                 mGraphicsPipelineDesc->updateRasterizationSamples(&mGraphicsPipelineTransition,
2913                                                                   mDrawFramebuffer->getSamples());
2914                 mGraphicsPipelineDesc->updateFrontFace(&mGraphicsPipelineTransition,
2915                                                        glState.getRasterizerState(),
2916                                                        isViewportFlipEnabledForDrawFBO());
2917                 ANGLE_TRY(updateScissor(glState));
2918                 const gl::DepthStencilState depthStencilState = glState.getDepthStencilState();
2919                 mGraphicsPipelineDesc->updateDepthTestEnabled(&mGraphicsPipelineTransition,
2920                                                               depthStencilState, drawFramebuffer);
2921                 mGraphicsPipelineDesc->updateDepthWriteEnabled(&mGraphicsPipelineTransition,
2922                                                                depthStencilState, drawFramebuffer);
2923                 mGraphicsPipelineDesc->updateStencilTestEnabled(&mGraphicsPipelineTransition,
2924                                                                 depthStencilState, drawFramebuffer);
2925                 mGraphicsPipelineDesc->updateStencilFrontWriteMask(
2926                     &mGraphicsPipelineTransition, depthStencilState, drawFramebuffer);
2927                 mGraphicsPipelineDesc->updateStencilBackWriteMask(
2928                     &mGraphicsPipelineTransition, depthStencilState, drawFramebuffer);
2929                 mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition,
2930                                                             mDrawFramebuffer->getRenderPassDesc());
2931                 invalidateCurrentTransformFeedbackBuffers();
2932                 break;
2933             }
2934             case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING:
2935                 break;
2936             case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING:
2937             {
2938                 mVertexArray = vk::GetImpl(glState.getVertexArray());
2939                 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask());
2940                 mVertexArray->updateActiveAttribInfo(this);
2941                 setIndexBufferDirty();
2942                 break;
2943             }
2944             case gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING:
2945                 break;
2946             case gl::State::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING:
2947                 break;
2948             case gl::State::DIRTY_BIT_PROGRAM_BINDING:
2949                 invalidateProgramBindingHelper(glState);
2950                 break;
2951             case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
2952             {
2953                 ASSERT(programExecutable);
2954                 invalidateCurrentDefaultUniforms();
2955                 ASSERT(gl::State::DIRTY_BIT_TEXTURE_BINDINGS >
2956                        gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE);
2957                 iter.setLaterBit(gl::State::DIRTY_BIT_TEXTURE_BINDINGS);
2958                 invalidateCurrentShaderResources();
2959                 ANGLE_TRY(invalidateProgramExecutableHelper(context));
2960                 break;
2961             }
2962             case gl::State::DIRTY_BIT_SAMPLER_BINDINGS:
2963             {
2964                 ASSERT(gl::State::DIRTY_BIT_TEXTURE_BINDINGS >
2965                        gl::State::DIRTY_BIT_SAMPLER_BINDINGS);
2966                 iter.setLaterBit(gl::State::DIRTY_BIT_TEXTURE_BINDINGS);
2967                 break;
2968             }
2969             case gl::State::DIRTY_BIT_TEXTURE_BINDINGS:
2970                 ANGLE_TRY(invalidateCurrentTextures(context));
2971                 break;
2972             case gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING:
2973                 // Nothing to do.
2974                 break;
2975             case gl::State::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING:
2976                 invalidateCurrentShaderResources();
2977                 break;
2978             case gl::State::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS:
2979                 invalidateCurrentShaderResources();
2980                 break;
2981             case gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING:
2982                 invalidateCurrentShaderResources();
2983                 invalidateDriverUniforms();
2984                 break;
2985             case gl::State::DIRTY_BIT_IMAGE_BINDINGS:
2986                 invalidateCurrentShaderResources();
2987                 break;
2988             case gl::State::DIRTY_BIT_MULTISAMPLING:
2989                 // TODO(syoussefi): this should configure the pipeline to render as if
2990                 // single-sampled, and write the results to all samples of a pixel regardless of
2991                 // coverage. See EXT_multisample_compatibility.  http://anglebug.com/3204
2992                 break;
2993             case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_ONE:
2994                 // TODO(syoussefi): this is part of EXT_multisample_compatibility.  The
2995                 // alphaToOne Vulkan feature should be enabled to support this extension.
2996                 // http://anglebug.com/3204
2997                 mGraphicsPipelineDesc->updateAlphaToOneEnable(&mGraphicsPipelineTransition,
2998                                                               glState.isSampleAlphaToOneEnabled());
2999                 break;
3000             case gl::State::DIRTY_BIT_COVERAGE_MODULATION:
3001                 break;
3002             case gl::State::DIRTY_BIT_FRAMEBUFFER_SRGB:
3003                 break;
3004             case gl::State::DIRTY_BIT_CURRENT_VALUES:
3005             {
3006                 invalidateDefaultAttributes(glState.getAndResetDirtyCurrentValues());
3007                 break;
3008             }
3009             case gl::State::DIRTY_BIT_PROVOKING_VERTEX:
3010                 break;
3011             default:
3012                 UNREACHABLE();
3013                 break;
3014         }
3015     }
3016 
3017     return angle::Result::Continue;
3018 }
3019 
getGPUDisjoint()3020 GLint ContextVk::getGPUDisjoint()
3021 {
3022     // No extension seems to be available to query this information.
3023     return 0;
3024 }
3025 
getTimestamp()3026 GLint64 ContextVk::getTimestamp()
3027 {
3028     // This function should only be called if timestamp queries are available.
3029     ASSERT(mRenderer->getQueueFamilyProperties().timestampValidBits > 0);
3030 
3031     uint64_t timestamp = 0;
3032 
3033     (void)getTimestamp(&timestamp);
3034 
3035     return static_cast<GLint64>(timestamp);
3036 }
3037 
onMakeCurrent(const gl::Context * context)3038 angle::Result ContextVk::onMakeCurrent(const gl::Context *context)
3039 {
3040     mRenderer->reloadVolkIfNeeded();
3041 
3042     // Flip viewports if FeaturesVk::flipViewportY is enabled and the user did not request that
3043     // the surface is flipped.
3044     egl::Surface *drawSurface = context->getCurrentDrawSurface();
3045     mFlipYForCurrentSurface =
3046         drawSurface != nullptr && mRenderer->getFeatures().flipViewportY.enabled &&
3047         !IsMaskFlagSet(drawSurface->getOrientation(), EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE);
3048 
3049     if (drawSurface && drawSurface->getType() == EGL_WINDOW_BIT)
3050     {
3051         mCurrentWindowSurface = GetImplAs<WindowSurfaceVk>(drawSurface);
3052     }
3053     else
3054     {
3055         mCurrentWindowSurface = nullptr;
3056     }
3057 
3058     const gl::State &glState = context->getState();
3059     updateFlipViewportDrawFramebuffer(glState);
3060     updateFlipViewportReadFramebuffer(glState);
3061     updateSurfaceRotationDrawFramebuffer(glState);
3062     updateSurfaceRotationReadFramebuffer(glState);
3063     invalidateDriverUniforms();
3064 
3065     return angle::Result::Continue;
3066 }
3067 
onUnMakeCurrent(const gl::Context * context)3068 angle::Result ContextVk::onUnMakeCurrent(const gl::Context *context)
3069 {
3070     ANGLE_TRY(flushImpl(nullptr));
3071     mCurrentWindowSurface = nullptr;
3072     return angle::Result::Continue;
3073 }
3074 
updateFlipViewportDrawFramebuffer(const gl::State & glState)3075 void ContextVk::updateFlipViewportDrawFramebuffer(const gl::State &glState)
3076 {
3077     gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
3078     mFlipViewportForDrawFramebuffer =
3079         drawFramebuffer->isDefault() && mRenderer->getFeatures().flipViewportY.enabled;
3080 }
3081 
updateFlipViewportReadFramebuffer(const gl::State & glState)3082 void ContextVk::updateFlipViewportReadFramebuffer(const gl::State &glState)
3083 {
3084     gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
3085     mFlipViewportForReadFramebuffer =
3086         readFramebuffer->isDefault() && mRenderer->getFeatures().flipViewportY.enabled;
3087 }
3088 
updateSurfaceRotationDrawFramebuffer(const gl::State & glState)3089 void ContextVk::updateSurfaceRotationDrawFramebuffer(const gl::State &glState)
3090 {
3091     gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
3092     mCurrentRotationDrawFramebuffer =
3093         DetermineSurfaceRotation(drawFramebuffer, mCurrentWindowSurface);
3094 }
3095 
updateSurfaceRotationReadFramebuffer(const gl::State & glState)3096 void ContextVk::updateSurfaceRotationReadFramebuffer(const gl::State &glState)
3097 {
3098     gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
3099     mCurrentRotationDrawFramebuffer =
3100         DetermineSurfaceRotation(readFramebuffer, mCurrentWindowSurface);
3101 }
3102 
getNativeCaps() const3103 gl::Caps ContextVk::getNativeCaps() const
3104 {
3105     return mRenderer->getNativeCaps();
3106 }
3107 
getNativeTextureCaps() const3108 const gl::TextureCapsMap &ContextVk::getNativeTextureCaps() const
3109 {
3110     return mRenderer->getNativeTextureCaps();
3111 }
3112 
getNativeExtensions() const3113 const gl::Extensions &ContextVk::getNativeExtensions() const
3114 {
3115     return mRenderer->getNativeExtensions();
3116 }
3117 
getNativeLimitations() const3118 const gl::Limitations &ContextVk::getNativeLimitations() const
3119 {
3120     return mRenderer->getNativeLimitations();
3121 }
3122 
createCompiler()3123 CompilerImpl *ContextVk::createCompiler()
3124 {
3125     return new CompilerVk();
3126 }
3127 
createShader(const gl::ShaderState & state)3128 ShaderImpl *ContextVk::createShader(const gl::ShaderState &state)
3129 {
3130     return new ShaderVk(state);
3131 }
3132 
createProgram(const gl::ProgramState & state)3133 ProgramImpl *ContextVk::createProgram(const gl::ProgramState &state)
3134 {
3135     return new ProgramVk(state);
3136 }
3137 
createFramebuffer(const gl::FramebufferState & state)3138 FramebufferImpl *ContextVk::createFramebuffer(const gl::FramebufferState &state)
3139 {
3140     return FramebufferVk::CreateUserFBO(mRenderer, state);
3141 }
3142 
createTexture(const gl::TextureState & state)3143 TextureImpl *ContextVk::createTexture(const gl::TextureState &state)
3144 {
3145     return new TextureVk(state, mRenderer);
3146 }
3147 
createRenderbuffer(const gl::RenderbufferState & state)3148 RenderbufferImpl *ContextVk::createRenderbuffer(const gl::RenderbufferState &state)
3149 {
3150     return new RenderbufferVk(state);
3151 }
3152 
createBuffer(const gl::BufferState & state)3153 BufferImpl *ContextVk::createBuffer(const gl::BufferState &state)
3154 {
3155     return new BufferVk(state);
3156 }
3157 
createVertexArray(const gl::VertexArrayState & state)3158 VertexArrayImpl *ContextVk::createVertexArray(const gl::VertexArrayState &state)
3159 {
3160     return new VertexArrayVk(this, state);
3161 }
3162 
createQuery(gl::QueryType type)3163 QueryImpl *ContextVk::createQuery(gl::QueryType type)
3164 {
3165     return new QueryVk(type);
3166 }
3167 
createFenceNV()3168 FenceNVImpl *ContextVk::createFenceNV()
3169 {
3170     return new FenceNVVk();
3171 }
3172 
createSync()3173 SyncImpl *ContextVk::createSync()
3174 {
3175     return new SyncVk();
3176 }
3177 
createTransformFeedback(const gl::TransformFeedbackState & state)3178 TransformFeedbackImpl *ContextVk::createTransformFeedback(const gl::TransformFeedbackState &state)
3179 {
3180     return new TransformFeedbackVk(state);
3181 }
3182 
createSampler(const gl::SamplerState & state)3183 SamplerImpl *ContextVk::createSampler(const gl::SamplerState &state)
3184 {
3185     return new SamplerVk(state);
3186 }
3187 
createProgramPipeline(const gl::ProgramPipelineState & state)3188 ProgramPipelineImpl *ContextVk::createProgramPipeline(const gl::ProgramPipelineState &state)
3189 {
3190     return new ProgramPipelineVk(state);
3191 }
3192 
createMemoryObject()3193 MemoryObjectImpl *ContextVk::createMemoryObject()
3194 {
3195     return new MemoryObjectVk();
3196 }
3197 
createSemaphore()3198 SemaphoreImpl *ContextVk::createSemaphore()
3199 {
3200     return new SemaphoreVk();
3201 }
3202 
createOverlay(const gl::OverlayState & state)3203 OverlayImpl *ContextVk::createOverlay(const gl::OverlayState &state)
3204 {
3205     return new OverlayVk(state);
3206 }
3207 
invalidateCurrentDefaultUniforms()3208 void ContextVk::invalidateCurrentDefaultUniforms()
3209 {
3210     const gl::ProgramExecutable *executable = mState.getProgramExecutable();
3211     ASSERT(executable);
3212 
3213     if (executable->hasDefaultUniforms())
3214     {
3215         mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
3216         mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
3217     }
3218 }
3219 
invalidateCurrentTextures(const gl::Context * context)3220 angle::Result ContextVk::invalidateCurrentTextures(const gl::Context *context)
3221 {
3222     const gl::ProgramExecutable *executable = mState.getProgramExecutable();
3223     ASSERT(executable);
3224 
3225     if (executable->hasTextures())
3226     {
3227         mGraphicsDirtyBits.set(DIRTY_BIT_TEXTURES);
3228         mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
3229         mComputeDirtyBits.set(DIRTY_BIT_TEXTURES);
3230         mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
3231 
3232         ANGLE_TRY(updateActiveTextures(context));
3233     }
3234 
3235     return angle::Result::Continue;
3236 }
3237 
invalidateCurrentShaderResources()3238 void ContextVk::invalidateCurrentShaderResources()
3239 {
3240     const gl::ProgramExecutable *executable = mState.getProgramExecutable();
3241     ASSERT(executable);
3242 
3243     if (executable->hasUniformBuffers() || executable->hasStorageBuffers() ||
3244         executable->hasAtomicCounterBuffers() || executable->hasImages())
3245     {
3246         mGraphicsDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES);
3247         mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
3248         mComputeDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES);
3249         mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
3250     }
3251 }
3252 
invalidateGraphicsDriverUniforms()3253 void ContextVk::invalidateGraphicsDriverUniforms()
3254 {
3255     mGraphicsDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS);
3256     mGraphicsDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING);
3257 }
3258 
invalidateDriverUniforms()3259 void ContextVk::invalidateDriverUniforms()
3260 {
3261     mGraphicsDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS);
3262     mGraphicsDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING);
3263     mComputeDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS);
3264     mComputeDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING);
3265 }
3266 
onDrawFramebufferChange(FramebufferVk * framebufferVk)3267 void ContextVk::onDrawFramebufferChange(FramebufferVk *framebufferVk)
3268 {
3269     const vk::RenderPassDesc &renderPassDesc = framebufferVk->getRenderPassDesc();
3270 
3271     // Ensure that the RenderPass description is updated.
3272     invalidateCurrentGraphicsPipeline();
3273     if (mGraphicsPipelineDesc->getRasterizationSamples() !=
3274         static_cast<uint32_t>(framebufferVk->getSamples()))
3275     {
3276         mGraphicsPipelineDesc->updateRasterizationSamples(&mGraphicsPipelineTransition,
3277                                                           framebufferVk->getSamples());
3278     }
3279     mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition, renderPassDesc);
3280 }
3281 
invalidateCurrentTransformFeedbackBuffers()3282 void ContextVk::invalidateCurrentTransformFeedbackBuffers()
3283 {
3284     if (getFeatures().supportsTransformFeedbackExtension.enabled)
3285     {
3286         mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
3287     }
3288     if (getFeatures().emulateTransformFeedback.enabled)
3289     {
3290         mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
3291     }
3292 }
3293 
invalidateCurrentTransformFeedbackState()3294 void ContextVk::invalidateCurrentTransformFeedbackState()
3295 {
3296     mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_STATE);
3297 }
3298 
onTransformFeedbackStateChanged()3299 void ContextVk::onTransformFeedbackStateChanged()
3300 {
3301     if (getFeatures().supportsTransformFeedbackExtension.enabled)
3302     {
3303         invalidateCurrentTransformFeedbackState();
3304     }
3305     else if (getFeatures().emulateTransformFeedback.enabled)
3306     {
3307         invalidateGraphicsDriverUniforms();
3308     }
3309 }
3310 
invalidateGraphicsDescriptorSet(uint32_t usedDescriptorSet)3311 void ContextVk::invalidateGraphicsDescriptorSet(uint32_t usedDescriptorSet)
3312 {
3313     // UtilsVk currently only uses set 0
3314     ASSERT(usedDescriptorSet == kDriverUniformsDescriptorSetIndex);
3315     if (mDriverUniforms[PipelineType::Graphics].descriptorSet != VK_NULL_HANDLE)
3316     {
3317         mGraphicsDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING);
3318     }
3319 }
3320 
invalidateComputeDescriptorSet(uint32_t usedDescriptorSet)3321 void ContextVk::invalidateComputeDescriptorSet(uint32_t usedDescriptorSet)
3322 {
3323     // UtilsVk currently only uses set 0
3324     ASSERT(usedDescriptorSet == kDriverUniformsDescriptorSetIndex);
3325     if (mDriverUniforms[PipelineType::Compute].descriptorSet != VK_NULL_HANDLE)
3326     {
3327         mComputeDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING);
3328     }
3329 }
3330 
dispatchCompute(const gl::Context * context,GLuint numGroupsX,GLuint numGroupsY,GLuint numGroupsZ)3331 angle::Result ContextVk::dispatchCompute(const gl::Context *context,
3332                                          GLuint numGroupsX,
3333                                          GLuint numGroupsY,
3334                                          GLuint numGroupsZ)
3335 {
3336     vk::CommandBuffer *commandBuffer;
3337     ANGLE_TRY(setupDispatch(context, &commandBuffer));
3338 
3339     commandBuffer->dispatch(numGroupsX, numGroupsY, numGroupsZ);
3340 
3341     return angle::Result::Continue;
3342 }
3343 
dispatchComputeIndirect(const gl::Context * context,GLintptr indirect)3344 angle::Result ContextVk::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect)
3345 {
3346     vk::CommandBuffer *commandBuffer;
3347     ANGLE_TRY(setupDispatch(context, &commandBuffer));
3348 
3349     gl::Buffer *glBuffer     = getState().getTargetBuffer(gl::BufferBinding::DispatchIndirect);
3350     vk::BufferHelper &buffer = vk::GetImpl(glBuffer)->getBuffer();
3351     mOutsideRenderPassCommands.bufferRead(&mResourceUseList, VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
3352                                           &buffer);
3353 
3354     commandBuffer->dispatchIndirect(buffer.getBuffer(), indirect);
3355 
3356     return angle::Result::Continue;
3357 }
3358 
memoryBarrier(const gl::Context * context,GLbitfield barriers)3359 angle::Result ContextVk::memoryBarrier(const gl::Context *context, GLbitfield barriers)
3360 {
3361     return memoryBarrierImpl(barriers, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
3362 }
3363 
memoryBarrierByRegion(const gl::Context * context,GLbitfield barriers)3364 angle::Result ContextVk::memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers)
3365 {
3366     // Note: memoryBarrierByRegion is expected to affect only the fragment pipeline, but is
3367     // otherwise similar to memoryBarrier.
3368 
3369     return memoryBarrierImpl(barriers, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
3370 }
3371 
memoryBarrierImpl(GLbitfield barriers,VkPipelineStageFlags stageMask)3372 angle::Result ContextVk::memoryBarrierImpl(GLbitfield barriers, VkPipelineStageFlags stageMask)
3373 {
3374     // Note: many of the barriers specified here are already covered automatically.
3375     //
3376     // The barriers that are necessary all have SHADER_WRITE as src access and the dst access is
3377     // determined by the given bitfield.  Currently, all image-related barriers that require the
3378     // image to change usage are handled through image layout transitions.  Most buffer-related
3379     // barriers where the buffer usage changes are also handled automatically through dirty bits.
3380     // The only barriers that are necessary are thus barriers in situations where the resource can
3381     // be written to and read from without changing the bindings.
3382 
3383     VkAccessFlags srcAccess = 0;
3384     VkAccessFlags dstAccess = 0;
3385 
3386     // Both IMAGE_ACCESS and STORAGE barrier flags translate to the same Vulkan dst access mask.
3387     constexpr GLbitfield kShaderWriteBarriers =
3388         GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT;
3389 
3390     if ((barriers & kShaderWriteBarriers) != 0)
3391     {
3392         srcAccess |= VK_ACCESS_SHADER_WRITE_BIT;
3393         dstAccess |= VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;
3394     }
3395 
3396     vk::CommandBuffer *commandBuffer;
3397     ANGLE_TRY(endRenderPassAndGetCommandBuffer(&commandBuffer));
3398 
3399     VkMemoryBarrier memoryBarrier = {};
3400     memoryBarrier.sType           = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
3401     memoryBarrier.srcAccessMask   = srcAccess;
3402     memoryBarrier.dstAccessMask   = dstAccess;
3403 
3404     commandBuffer->memoryBarrier(stageMask, stageMask, &memoryBarrier);
3405 
3406     return angle::Result::Continue;
3407 }
3408 
getQueryPool(gl::QueryType queryType)3409 vk::DynamicQueryPool *ContextVk::getQueryPool(gl::QueryType queryType)
3410 {
3411     ASSERT(queryType == gl::QueryType::AnySamples ||
3412            queryType == gl::QueryType::AnySamplesConservative ||
3413            queryType == gl::QueryType::Timestamp || queryType == gl::QueryType::TimeElapsed);
3414 
3415     // Assert that timestamp extension is available if needed.
3416     ASSERT(queryType != gl::QueryType::Timestamp && queryType != gl::QueryType::TimeElapsed ||
3417            mRenderer->getQueueFamilyProperties().timestampValidBits > 0);
3418     ASSERT(mQueryPools[queryType].isValid());
3419     return &mQueryPools[queryType];
3420 }
3421 
getClearColorValue() const3422 const VkClearValue &ContextVk::getClearColorValue() const
3423 {
3424     return mClearColorValue;
3425 }
3426 
getClearDepthStencilValue() const3427 const VkClearValue &ContextVk::getClearDepthStencilValue() const
3428 {
3429     return mClearDepthStencilValue;
3430 }
3431 
getClearColorMask() const3432 VkColorComponentFlags ContextVk::getClearColorMask() const
3433 {
3434     return mClearColorMask;
3435 }
3436 
writeAtomicCounterBufferDriverUniformOffsets(uint32_t * offsetsOut,size_t offsetsSize)3437 void ContextVk::writeAtomicCounterBufferDriverUniformOffsets(uint32_t *offsetsOut,
3438                                                              size_t offsetsSize)
3439 {
3440     const VkDeviceSize offsetAlignment =
3441         mRenderer->getPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
3442     size_t atomicCounterBufferCount = mState.getAtomicCounterBufferCount();
3443 
3444     ASSERT(atomicCounterBufferCount <= offsetsSize * 4);
3445 
3446     for (uint32_t bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
3447     {
3448         uint32_t offsetDiff = 0;
3449 
3450         const gl::OffsetBindingPointer<gl::Buffer> *atomicCounterBuffer =
3451             &mState.getIndexedAtomicCounterBuffer(bufferIndex);
3452         if (atomicCounterBuffer->get())
3453         {
3454             VkDeviceSize offset        = atomicCounterBuffer->getOffset();
3455             VkDeviceSize alignedOffset = (offset / offsetAlignment) * offsetAlignment;
3456 
3457             // GL requires the atomic counter buffer offset to be aligned with uint.
3458             ASSERT((offset - alignedOffset) % sizeof(uint32_t) == 0);
3459             offsetDiff = static_cast<uint32_t>((offset - alignedOffset) / sizeof(uint32_t));
3460 
3461             // We expect offsetDiff to fit in an 8-bit value.  The maximum difference is
3462             // minStorageBufferOffsetAlignment / 4, where minStorageBufferOffsetAlignment
3463             // currently has a maximum value of 256 on any device.
3464             ASSERT(offsetDiff < (1 << 8));
3465         }
3466 
3467         // The output array is already cleared prior to this call.
3468         ASSERT(bufferIndex % 4 != 0 || offsetsOut[bufferIndex / 4] == 0);
3469 
3470         offsetsOut[bufferIndex / 4] |= static_cast<uint8_t>(offsetDiff) << ((bufferIndex % 4) * 8);
3471     }
3472 }
3473 
handleDirtyGraphicsDriverUniforms(const gl::Context * context,vk::CommandBuffer * commandBuffer)3474 angle::Result ContextVk::handleDirtyGraphicsDriverUniforms(const gl::Context *context,
3475                                                            vk::CommandBuffer *commandBuffer)
3476 {
3477     // Allocate a new region in the dynamic buffer.
3478     uint8_t *ptr;
3479     VkBuffer buffer;
3480     bool newBuffer;
3481     ANGLE_TRY(allocateDriverUniforms(sizeof(GraphicsDriverUniforms),
3482                                      &mDriverUniforms[PipelineType::Graphics], &buffer, &ptr,
3483                                      &newBuffer));
3484 
3485     gl::Rectangle glViewport = mState.getViewport();
3486     float halfRenderAreaHeight =
3487         static_cast<float>(mDrawFramebuffer->getState().getDimensions().height) * 0.5f;
3488     if (isRotatedAspectRatioForDrawFBO())
3489     {
3490         // The surface is rotated 90/270 degrees.  This changes the aspect ratio of the surface.
3491         // TODO(ianelliott): handle small viewport/scissor cases.  http://anglebug.com/4431
3492         std::swap(glViewport.width, glViewport.height);
3493         halfRenderAreaHeight =
3494             static_cast<float>(mDrawFramebuffer->getState().getDimensions().width) * 0.5f;
3495     }
3496     float scaleY = isViewportFlipEnabledForDrawFBO() ? -1.0f : 1.0f;
3497 
3498     uint32_t xfbActiveUnpaused = mState.isTransformFeedbackActiveUnpaused();
3499 
3500     float depthRangeNear = mState.getNearPlane();
3501     float depthRangeFar  = mState.getFarPlane();
3502     float depthRangeDiff = depthRangeFar - depthRangeNear;
3503 
3504     // Copy and flush to the device.
3505     GraphicsDriverUniforms *driverUniforms = reinterpret_cast<GraphicsDriverUniforms *>(ptr);
3506     *driverUniforms                        = {
3507         {static_cast<float>(glViewport.x), static_cast<float>(glViewport.y),
3508          static_cast<float>(glViewport.width), static_cast<float>(glViewport.height)},
3509         halfRenderAreaHeight,
3510         scaleY,
3511         -scaleY,
3512         xfbActiveUnpaused,
3513         mXfbVertexCountPerInstance,
3514         {},
3515         {},
3516         {},
3517         {depthRangeNear, depthRangeFar, depthRangeDiff, 0.0f},
3518         {}};
3519     memcpy(&driverUniforms->preRotation, &kPreRotationMatrices[mCurrentRotationDrawFramebuffer],
3520            sizeof(PreRotationMatrixValues));
3521 
3522     if (xfbActiveUnpaused)
3523     {
3524         TransformFeedbackVk *transformFeedbackVk =
3525             vk::GetImpl(mState.getCurrentTransformFeedback());
3526         transformFeedbackVk->getBufferOffsets(this, mXfbBaseVertex,
3527                                               driverUniforms->xfbBufferOffsets.data(),
3528                                               driverUniforms->xfbBufferOffsets.size());
3529     }
3530 
3531     writeAtomicCounterBufferDriverUniformOffsets(driverUniforms->acbBufferOffsets.data(),
3532                                                  driverUniforms->acbBufferOffsets.size());
3533 
3534     return updateDriverUniformsDescriptorSet(buffer, newBuffer, sizeof(GraphicsDriverUniforms),
3535                                              &mDriverUniforms[PipelineType::Graphics]);
3536 }
3537 
handleDirtyComputeDriverUniforms(const gl::Context * context,vk::CommandBuffer * commandBuffer)3538 angle::Result ContextVk::handleDirtyComputeDriverUniforms(const gl::Context *context,
3539                                                           vk::CommandBuffer *commandBuffer)
3540 {
3541     // Allocate a new region in the dynamic buffer.
3542     uint8_t *ptr;
3543     VkBuffer buffer;
3544     bool newBuffer;
3545     ANGLE_TRY(allocateDriverUniforms(sizeof(ComputeDriverUniforms),
3546                                      &mDriverUniforms[PipelineType::Compute], &buffer, &ptr,
3547                                      &newBuffer));
3548 
3549     // Copy and flush to the device.
3550     ComputeDriverUniforms *driverUniforms = reinterpret_cast<ComputeDriverUniforms *>(ptr);
3551     *driverUniforms                       = {};
3552 
3553     writeAtomicCounterBufferDriverUniformOffsets(driverUniforms->acbBufferOffsets.data(),
3554                                                  driverUniforms->acbBufferOffsets.size());
3555 
3556     return updateDriverUniformsDescriptorSet(buffer, newBuffer, sizeof(ComputeDriverUniforms),
3557                                              &mDriverUniforms[PipelineType::Compute]);
3558 }
3559 
handleDirtyDriverUniformsBindingImpl(vk::CommandBuffer * commandBuffer,VkPipelineBindPoint bindPoint,const DriverUniformsDescriptorSet & driverUniforms)3560 void ContextVk::handleDirtyDriverUniformsBindingImpl(
3561     vk::CommandBuffer *commandBuffer,
3562     VkPipelineBindPoint bindPoint,
3563     const DriverUniformsDescriptorSet &driverUniforms)
3564 {
3565     commandBuffer->bindDescriptorSets(
3566         mExecutable->getPipelineLayout(), bindPoint, kDriverUniformsDescriptorSetIndex, 1,
3567         &driverUniforms.descriptorSet, 1, &driverUniforms.dynamicOffset);
3568 }
3569 
handleDirtyGraphicsDriverUniformsBinding(const gl::Context * context,vk::CommandBuffer * commandBuffer)3570 angle::Result ContextVk::handleDirtyGraphicsDriverUniformsBinding(const gl::Context *context,
3571                                                                   vk::CommandBuffer *commandBuffer)
3572 {
3573     // Bind the driver descriptor set.
3574     handleDirtyDriverUniformsBindingImpl(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
3575                                          mDriverUniforms[PipelineType::Graphics]);
3576     return angle::Result::Continue;
3577 }
3578 
handleDirtyComputeDriverUniformsBinding(const gl::Context * context,vk::CommandBuffer * commandBuffer)3579 angle::Result ContextVk::handleDirtyComputeDriverUniformsBinding(const gl::Context *context,
3580                                                                  vk::CommandBuffer *commandBuffer)
3581 {
3582     // Bind the driver descriptor set.
3583     handleDirtyDriverUniformsBindingImpl(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE,
3584                                          mDriverUniforms[PipelineType::Compute]);
3585     return angle::Result::Continue;
3586 }
3587 
allocateDriverUniforms(size_t driverUniformsSize,DriverUniformsDescriptorSet * driverUniforms,VkBuffer * bufferOut,uint8_t ** ptrOut,bool * newBufferOut)3588 angle::Result ContextVk::allocateDriverUniforms(size_t driverUniformsSize,
3589                                                 DriverUniformsDescriptorSet *driverUniforms,
3590                                                 VkBuffer *bufferOut,
3591                                                 uint8_t **ptrOut,
3592                                                 bool *newBufferOut)
3593 {
3594     // Release any previously retained buffers.
3595     driverUniforms->dynamicBuffer.releaseInFlightBuffers(this);
3596 
3597     // Allocate a new region in the dynamic buffer.
3598     VkDeviceSize offset;
3599     ANGLE_TRY(driverUniforms->dynamicBuffer.allocate(this, driverUniformsSize, ptrOut, bufferOut,
3600                                                      &offset, newBufferOut));
3601 
3602     driverUniforms->dynamicOffset = static_cast<uint32_t>(offset);
3603 
3604     return angle::Result::Continue;
3605 }
3606 
updateDriverUniformsDescriptorSet(VkBuffer buffer,bool newBuffer,size_t driverUniformsSize,DriverUniformsDescriptorSet * driverUniforms)3607 angle::Result ContextVk::updateDriverUniformsDescriptorSet(
3608     VkBuffer buffer,
3609     bool newBuffer,
3610     size_t driverUniformsSize,
3611     DriverUniformsDescriptorSet *driverUniforms)
3612 {
3613     ANGLE_TRY(driverUniforms->dynamicBuffer.flush(this));
3614 
3615     if (!newBuffer)
3616     {
3617         return angle::Result::Continue;
3618     }
3619 
3620     // Allocate a new descriptor set.
3621     ANGLE_TRY(mDriverUniformsDescriptorPool.allocateSets(
3622         this, driverUniforms->descriptorSetLayout.get().ptr(), 1,
3623         &driverUniforms->descriptorPoolBinding, &driverUniforms->descriptorSet));
3624 
3625     // Update the driver uniform descriptor set.
3626     VkDescriptorBufferInfo bufferInfo = {};
3627     bufferInfo.buffer                 = buffer;
3628     bufferInfo.offset                 = 0;
3629     bufferInfo.range                  = driverUniformsSize;
3630 
3631     VkWriteDescriptorSet writeInfo = {};
3632     writeInfo.sType                = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3633     writeInfo.dstSet               = driverUniforms->descriptorSet;
3634     writeInfo.dstBinding           = 0;
3635     writeInfo.dstArrayElement      = 0;
3636     writeInfo.descriptorCount      = 1;
3637     writeInfo.descriptorType       = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
3638     writeInfo.pImageInfo           = nullptr;
3639     writeInfo.pTexelBufferView     = nullptr;
3640     writeInfo.pBufferInfo          = &bufferInfo;
3641 
3642     vkUpdateDescriptorSets(getDevice(), 1, &writeInfo, 0, nullptr);
3643 
3644     return angle::Result::Continue;
3645 }
3646 
handleError(VkResult errorCode,const char * file,const char * function,unsigned int line)3647 void ContextVk::handleError(VkResult errorCode,
3648                             const char *file,
3649                             const char *function,
3650                             unsigned int line)
3651 {
3652     ASSERT(errorCode != VK_SUCCESS);
3653 
3654     GLenum glErrorCode = DefaultGLErrorCode(errorCode);
3655 
3656     std::stringstream errorStream;
3657     errorStream << "Internal Vulkan error: " << VulkanResultString(errorCode) << ".";
3658 
3659     if (errorCode == VK_ERROR_DEVICE_LOST)
3660     {
3661         WARN() << errorStream.str();
3662         handleDeviceLost();
3663     }
3664 
3665     mErrors->handleError(glErrorCode, errorStream.str().c_str(), file, function, line);
3666 }
3667 
updateActiveTextures(const gl::Context * context)3668 angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
3669 {
3670     const gl::State &glState                = mState;
3671     const gl::ProgramExecutable *executable = glState.getProgramExecutable();
3672     ASSERT(executable);
3673 
3674     uint32_t prevMaxIndex = mActiveTexturesDesc.getMaxIndex();
3675     memset(mActiveTextures.data(), 0, sizeof(mActiveTextures[0]) * prevMaxIndex);
3676     mActiveTexturesDesc.reset();
3677 
3678     const gl::ActiveTexturesCache &textures        = glState.getActiveTexturesCache();
3679     const gl::ActiveTextureMask &activeTextures    = executable->getActiveSamplersMask();
3680     const gl::ActiveTextureTypeArray &textureTypes = executable->getActiveSamplerTypes();
3681 
3682     for (size_t textureUnit : activeTextures)
3683     {
3684         gl::Texture *texture        = textures[textureUnit];
3685         gl::Sampler *sampler        = mState.getSampler(static_cast<uint32_t>(textureUnit));
3686         gl::TextureType textureType = textureTypes[textureUnit];
3687 
3688         // Null textures represent incomplete textures.
3689         if (texture == nullptr)
3690         {
3691             ANGLE_TRY(getIncompleteTexture(context, textureType, &texture));
3692         }
3693 
3694         TextureVk *textureVk = vk::GetImpl(texture);
3695 
3696         SamplerVk *samplerVk;
3697         Serial samplerSerial;
3698         if (sampler == nullptr)
3699         {
3700             samplerVk     = nullptr;
3701             samplerSerial = rx::kZeroSerial;
3702         }
3703         else
3704         {
3705             samplerVk     = vk::GetImpl(sampler);
3706             samplerSerial = samplerVk->getSerial();
3707         }
3708 
3709         mActiveTextures[textureUnit].texture = textureVk;
3710         mActiveTextures[textureUnit].sampler = samplerVk;
3711         // Cache serials from sampler and texture, but re-use texture if no sampler bound
3712         ASSERT(textureVk != nullptr);
3713         mActiveTexturesDesc.update(textureUnit, textureVk->getSerial(), samplerSerial);
3714     }
3715 
3716     return angle::Result::Continue;
3717 }
3718 
updateActiveImages(const gl::Context * context,CommandBufferHelper * commandBufferHelper)3719 angle::Result ContextVk::updateActiveImages(const gl::Context *context,
3720                                             CommandBufferHelper *commandBufferHelper)
3721 {
3722     const gl::State &glState                = mState;
3723     const gl::ProgramExecutable *executable = glState.getProgramExecutable();
3724     ASSERT(executable);
3725 
3726     mActiveImages.fill(nullptr);
3727 
3728     const gl::ActiveTextureMask &activeImages = executable->getActiveImagesMask();
3729     const gl::ActiveTextureArray<gl::ShaderBitSet> &activeImageShaderBits =
3730         executable->getActiveImageShaderBits();
3731 
3732     // Note: currently, the image layout is transitioned entirely even if only one level or layer is
3733     // used.  This is an issue if one subresource of the image is used as framebuffer attachment and
3734     // the other as image.  This is a similar issue to http://anglebug.com/2914.  Another issue
3735     // however is if multiple subresources of the same image are used at the same time.
3736     // Inefficiencies aside, setting write dependency on the same image multiple times is not
3737     // supported.  The following makes sure write dependencies are set only once per image.
3738     std::set<vk::ImageHelper *> alreadyProcessed;
3739 
3740     for (size_t imageUnitIndex : activeImages)
3741     {
3742         const gl::ImageUnit &imageUnit = glState.getImageUnit(imageUnitIndex);
3743         const gl::Texture *texture     = imageUnit.texture.get();
3744         if (texture == nullptr)
3745         {
3746             continue;
3747         }
3748 
3749         TextureVk *textureVk   = vk::GetImpl(texture);
3750         vk::ImageHelper *image = &textureVk->getImage();
3751 
3752         mActiveImages[imageUnitIndex] = textureVk;
3753 
3754         if (alreadyProcessed.find(image) != alreadyProcessed.end())
3755         {
3756             continue;
3757         }
3758         alreadyProcessed.insert(image);
3759 
3760         // The image should be flushed and ready to use at this point. There may still be
3761         // lingering staged updates in its staging buffer for unused texture mip levels or
3762         // layers. Therefore we can't verify it has no staged updates right here.
3763         vk::ImageLayout imageLayout;
3764         gl::ShaderBitSet shaderBits = activeImageShaderBits[imageUnitIndex];
3765         if (shaderBits.any())
3766         {
3767             gl::ShaderType shader = static_cast<gl::ShaderType>(gl::ScanForward(shaderBits.bits()));
3768             shaderBits.reset(shader);
3769             // This is accessed by multiple shaders
3770             if (shaderBits.any())
3771             {
3772                 imageLayout = vk::ImageLayout::AllGraphicsShadersReadWrite;
3773             }
3774             else
3775             {
3776                 imageLayout = kShaderWriteImageLayouts[shader];
3777             }
3778         }
3779         else
3780         {
3781             imageLayout = vk::ImageLayout::AllGraphicsShadersReadWrite;
3782         }
3783         VkImageAspectFlags aspectFlags = image->getAspectFlags();
3784 
3785         commandBufferHelper->imageWrite(&mResourceUseList, aspectFlags, imageLayout, image);
3786     }
3787 
3788     return angle::Result::Continue;
3789 }
3790 
insertWaitSemaphore(const vk::Semaphore * waitSemaphore)3791 void ContextVk::insertWaitSemaphore(const vk::Semaphore *waitSemaphore)
3792 {
3793     ASSERT(waitSemaphore);
3794     mWaitSemaphores.push_back(waitSemaphore->getHandle());
3795 }
3796 
shouldFlush()3797 bool ContextVk::shouldFlush()
3798 {
3799     return getRenderer()->shouldCleanupGarbage();
3800 }
3801 
hasRecordedCommands()3802 bool ContextVk::hasRecordedCommands()
3803 {
3804     return !mOutsideRenderPassCommands.empty() || !mRenderPassCommands.empty() ||
3805            mHasPrimaryCommands;
3806 }
3807 
flushImpl(const vk::Semaphore * signalSemaphore)3808 angle::Result ContextVk::flushImpl(const vk::Semaphore *signalSemaphore)
3809 {
3810     bool hasPendingSemaphore = signalSemaphore || !mWaitSemaphores.empty();
3811     if (!hasRecordedCommands() && !hasPendingSemaphore && !mGpuEventsEnabled)
3812     {
3813         return angle::Result::Continue;
3814     }
3815 
3816     ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::flush");
3817 
3818     flushOutsideRenderPassCommands();
3819     ANGLE_TRY(endRenderPass());
3820 
3821     if (mIsAnyHostVisibleBufferWritten)
3822     {
3823         // Make sure all writes to host-visible buffers are flushed.  We have no way of knowing
3824         // whether any buffer will be mapped for readback in the future, and we can't afford to
3825         // flush and wait on a one-pipeline-barrier command buffer on every map().
3826         VkMemoryBarrier memoryBarrier = {};
3827         memoryBarrier.sType           = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
3828         memoryBarrier.srcAccessMask   = VK_ACCESS_MEMORY_WRITE_BIT;
3829         memoryBarrier.dstAccessMask   = VK_ACCESS_HOST_READ_BIT;
3830 
3831         mPrimaryCommands.memoryBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
3832                                        VK_PIPELINE_STAGE_HOST_BIT, &memoryBarrier);
3833         mIsAnyHostVisibleBufferWritten = false;
3834     }
3835 
3836     if (mGpuEventsEnabled)
3837     {
3838         EventName eventName = GetTraceEventName("Primary", mPrimaryBufferCounter);
3839         ANGLE_TRY(traceGpuEvent(&mPrimaryCommands, TRACE_EVENT_PHASE_END, eventName));
3840     }
3841 
3842     ANGLE_VK_TRY(this, mPrimaryCommands.end());
3843 
3844     // Free secondary command pool allocations and restart command buffers with the new page.
3845     mPoolAllocator.pop();
3846     mPoolAllocator.push();
3847     mOutsideRenderPassCommands.reset();
3848     mRenderPassCommands.reset();
3849 
3850     Serial serial = getCurrentQueueSerial();
3851     mResourceUseList.releaseResourceUsesAndUpdateSerials(serial);
3852 
3853     waitForSwapchainImageIfNecessary();
3854 
3855     VkSubmitInfo submitInfo = {};
3856     InitializeSubmitInfo(&submitInfo, mPrimaryCommands, mWaitSemaphores, &mWaitSemaphoreStageMasks,
3857                          signalSemaphore);
3858 
3859     ANGLE_TRY(submitFrame(submitInfo, std::move(mPrimaryCommands)));
3860 
3861     ANGLE_TRY(startPrimaryCommandBuffer());
3862 
3863     mRenderPassCounter = 0;
3864     mWaitSemaphores.clear();
3865 
3866     mPrimaryBufferCounter++;
3867 
3868     if (mGpuEventsEnabled)
3869     {
3870         EventName eventName = GetTraceEventName("Primary", mPrimaryBufferCounter);
3871         ANGLE_TRY(traceGpuEvent(&mPrimaryCommands, TRACE_EVENT_PHASE_BEGIN, eventName));
3872     }
3873 
3874     return angle::Result::Continue;
3875 }
3876 
finishImpl()3877 angle::Result ContextVk::finishImpl()
3878 {
3879     ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::finish");
3880 
3881     ANGLE_TRY(flushImpl(nullptr));
3882 
3883     ANGLE_TRY(finishToSerial(getLastSubmittedQueueSerial()));
3884     ASSERT(!mCommandQueue.hasInFlightCommands());
3885 
3886     clearAllGarbage();
3887 
3888     if (mGpuEventsEnabled)
3889     {
3890         // This loop should in practice execute once since the queue is already idle.
3891         while (mInFlightGpuEventQueries.size() > 0)
3892         {
3893             ANGLE_TRY(checkCompletedGpuEvents());
3894         }
3895         // Recalculate the CPU/GPU time difference to account for clock drifting.  Avoid
3896         // unnecessary synchronization if there is no event to be adjusted (happens when
3897         // finish() gets called multiple times towards the end of the application).
3898         if (mGpuEvents.size() > 0)
3899         {
3900             ANGLE_TRY(synchronizeCpuGpuTime());
3901         }
3902     }
3903 
3904     return angle::Result::Continue;
3905 }
3906 
addWaitSemaphore(VkSemaphore semaphore)3907 void ContextVk::addWaitSemaphore(VkSemaphore semaphore)
3908 {
3909     mWaitSemaphores.push_back(semaphore);
3910 }
3911 
getCommandPool() const3912 const vk::CommandPool &ContextVk::getCommandPool() const
3913 {
3914     return mCommandPool;
3915 }
3916 
isSerialInUse(Serial serial) const3917 bool ContextVk::isSerialInUse(Serial serial) const
3918 {
3919     return serial > getLastCompletedQueueSerial();
3920 }
3921 
checkCompletedCommands()3922 angle::Result ContextVk::checkCompletedCommands()
3923 {
3924     return mCommandQueue.checkCompletedCommands(this);
3925 }
3926 
finishToSerial(Serial serial)3927 angle::Result ContextVk::finishToSerial(Serial serial)
3928 {
3929     return mCommandQueue.finishToSerial(this, serial, mRenderer->getMaxFenceWaitTimeNs());
3930 }
3931 
getCompatibleRenderPass(const vk::RenderPassDesc & desc,vk::RenderPass ** renderPassOut)3932 angle::Result ContextVk::getCompatibleRenderPass(const vk::RenderPassDesc &desc,
3933                                                  vk::RenderPass **renderPassOut)
3934 {
3935     return mRenderPassCache.getCompatibleRenderPass(this, getCurrentQueueSerial(), desc,
3936                                                     renderPassOut);
3937 }
3938 
getRenderPassWithOps(const vk::RenderPassDesc & desc,const vk::AttachmentOpsArray & ops,vk::RenderPass ** renderPassOut)3939 angle::Result ContextVk::getRenderPassWithOps(const vk::RenderPassDesc &desc,
3940                                               const vk::AttachmentOpsArray &ops,
3941                                               vk::RenderPass **renderPassOut)
3942 {
3943     return mRenderPassCache.getRenderPassWithOps(this, getCurrentQueueSerial(), desc, ops,
3944                                                  renderPassOut);
3945 }
3946 
ensureSubmitFenceInitialized()3947 angle::Result ContextVk::ensureSubmitFenceInitialized()
3948 {
3949     if (mSubmitFence.isReferenced())
3950     {
3951         return angle::Result::Continue;
3952     }
3953 
3954     return mRenderer->newSharedFence(this, &mSubmitFence);
3955 }
3956 
getNextSubmitFence(vk::Shared<vk::Fence> * sharedFenceOut)3957 angle::Result ContextVk::getNextSubmitFence(vk::Shared<vk::Fence> *sharedFenceOut)
3958 {
3959     ANGLE_TRY(ensureSubmitFenceInitialized());
3960 
3961     ASSERT(!sharedFenceOut->isReferenced());
3962     sharedFenceOut->copy(getDevice(), mSubmitFence);
3963     return angle::Result::Continue;
3964 }
3965 
getLastSubmittedFence() const3966 vk::Shared<vk::Fence> ContextVk::getLastSubmittedFence() const
3967 {
3968     return mCommandQueue.getLastSubmittedFence(this);
3969 }
3970 
getTimestamp(uint64_t * timestampOut)3971 angle::Result ContextVk::getTimestamp(uint64_t *timestampOut)
3972 {
3973     // The intent of this function is to query the timestamp without stalling the GPU.
3974     // Currently, that seems impossible, so instead, we are going to make a small submission
3975     // with just a timestamp query.  First, the disjoint timer query extension says:
3976     //
3977     // > This will return the GL time after all previous commands have reached the GL server but
3978     // have not yet necessarily executed.
3979     //
3980     // The previous commands may be deferred at the moment and not yet flushed. The wording allows
3981     // us to make a submission to get the timestamp without flushing.
3982     //
3983     // Second:
3984     //
3985     // > By using a combination of this synchronous get command and the asynchronous timestamp
3986     // query object target, applications can measure the latency between when commands reach the
3987     // GL server and when they are realized in the framebuffer.
3988     //
3989     // This fits with the above strategy as well, although inevitably we are possibly
3990     // introducing a GPU bubble.  This function directly generates a command buffer and submits
3991     // it instead of using the other member functions.  This is to avoid changing any state,
3992     // such as the queue serial.
3993 
3994     // Create a query used to receive the GPU timestamp
3995     VkDevice device = getDevice();
3996     vk::DeviceScoped<vk::DynamicQueryPool> timestampQueryPool(device);
3997     vk::QueryHelper timestampQuery;
3998     ANGLE_TRY(timestampQueryPool.get().init(this, VK_QUERY_TYPE_TIMESTAMP, 1));
3999     ANGLE_TRY(timestampQueryPool.get().allocateQuery(this, &timestampQuery));
4000 
4001     // Record the command buffer
4002     vk::DeviceScoped<vk::PrimaryCommandBuffer> commandBatch(device);
4003     vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get();
4004 
4005     ANGLE_TRY(mCommandQueue.allocatePrimaryCommandBuffer(this, mCommandPool, &commandBuffer));
4006 
4007     VkCommandBufferBeginInfo beginInfo = {};
4008     beginInfo.sType                    = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
4009     beginInfo.flags                    = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
4010     beginInfo.pInheritanceInfo         = nullptr;
4011 
4012     ANGLE_VK_TRY(this, commandBuffer.begin(beginInfo));
4013     timestampQuery.writeTimestamp(this, &commandBuffer);
4014     ANGLE_VK_TRY(this, commandBuffer.end());
4015 
4016     // Create fence for the submission
4017     VkFenceCreateInfo fenceInfo = {};
4018     fenceInfo.sType             = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
4019     fenceInfo.flags             = 0;
4020 
4021     vk::DeviceScoped<vk::Fence> fence(device);
4022     ANGLE_VK_TRY(this, fence.get().init(device, fenceInfo));
4023 
4024     // Submit the command buffer
4025     VkSubmitInfo submitInfo         = {};
4026     submitInfo.sType                = VK_STRUCTURE_TYPE_SUBMIT_INFO;
4027     submitInfo.waitSemaphoreCount   = 0;
4028     submitInfo.pWaitSemaphores      = nullptr;
4029     submitInfo.pWaitDstStageMask    = nullptr;
4030     submitInfo.commandBufferCount   = 1;
4031     submitInfo.pCommandBuffers      = commandBuffer.ptr();
4032     submitInfo.signalSemaphoreCount = 0;
4033     submitInfo.pSignalSemaphores    = nullptr;
4034 
4035     Serial throwAwaySerial;
4036     ANGLE_TRY(
4037         mRenderer->queueSubmit(this, mContextPriority, submitInfo, &fence.get(), &throwAwaySerial));
4038 
4039     // Wait for the submission to finish.  Given no semaphores, there is hope that it would execute
4040     // in parallel with what's already running on the GPU.
4041     ANGLE_VK_TRY(this, fence.get().wait(device, mRenderer->getMaxFenceWaitTimeNs()));
4042 
4043     // Get the query results
4044     ANGLE_TRY(timestampQuery.getUint64Result(this, timestampOut));
4045     timestampQueryPool.get().freeQuery(this, &timestampQuery);
4046 
4047     // Convert results to nanoseconds.
4048     *timestampOut = static_cast<uint64_t>(
4049         *timestampOut *
4050         static_cast<double>(getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod));
4051 
4052     return mCommandQueue.releasePrimaryCommandBuffer(this, commandBatch.release());
4053 }
4054 
invalidateDefaultAttribute(size_t attribIndex)4055 void ContextVk::invalidateDefaultAttribute(size_t attribIndex)
4056 {
4057     mDirtyDefaultAttribsMask.set(attribIndex);
4058     mGraphicsDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS);
4059 }
4060 
invalidateDefaultAttributes(const gl::AttributesMask & dirtyMask)4061 void ContextVk::invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask)
4062 {
4063     if (dirtyMask.any())
4064     {
4065         mDirtyDefaultAttribsMask |= dirtyMask;
4066         mGraphicsDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS);
4067     }
4068 }
4069 
updateDefaultAttribute(size_t attribIndex)4070 angle::Result ContextVk::updateDefaultAttribute(size_t attribIndex)
4071 {
4072     vk::DynamicBuffer &defaultBuffer = mDefaultAttribBuffers[attribIndex];
4073 
4074     defaultBuffer.releaseInFlightBuffers(this);
4075 
4076     uint8_t *ptr;
4077     VkBuffer bufferHandle = VK_NULL_HANDLE;
4078     VkDeviceSize offset   = 0;
4079     ANGLE_TRY(
4080         defaultBuffer.allocate(this, kDefaultValueSize, &ptr, &bufferHandle, &offset, nullptr));
4081 
4082     const gl::State &glState = mState;
4083     const gl::VertexAttribCurrentValueData &defaultValue =
4084         glState.getVertexAttribCurrentValues()[attribIndex];
4085     memcpy(ptr, &defaultValue.Values, kDefaultValueSize);
4086 
4087     ANGLE_TRY(defaultBuffer.flush(this));
4088 
4089     mVertexArray->updateDefaultAttrib(this, attribIndex, bufferHandle,
4090                                       defaultBuffer.getCurrentBuffer(),
4091                                       static_cast<uint32_t>(offset));
4092     return angle::Result::Continue;
4093 }
4094 
waitForSwapchainImageIfNecessary()4095 void ContextVk::waitForSwapchainImageIfNecessary()
4096 {
4097     if (mCurrentWindowSurface)
4098     {
4099         vk::Semaphore waitSemaphore = mCurrentWindowSurface->getAcquireImageSemaphore();
4100         if (waitSemaphore.valid())
4101         {
4102             addWaitSemaphore(waitSemaphore.getHandle());
4103             addGarbage(&waitSemaphore);
4104         }
4105     }
4106 }
4107 
getDriverUniformsDescriptorSetDesc(VkShaderStageFlags shaderStages) const4108 vk::DescriptorSetLayoutDesc ContextVk::getDriverUniformsDescriptorSetDesc(
4109     VkShaderStageFlags shaderStages) const
4110 {
4111     vk::DescriptorSetLayoutDesc desc;
4112     desc.update(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, shaderStages);
4113     return desc;
4114 }
4115 
shouldEmulateSeamfulCubeMapSampling() const4116 bool ContextVk::shouldEmulateSeamfulCubeMapSampling() const
4117 {
4118     // Only allow seamful cube map sampling in non-webgl ES2.
4119     if (mState.getClientMajorVersion() != 2 || mState.isWebGL())
4120     {
4121         return false;
4122     }
4123 
4124     if (mRenderer->getFeatures().disallowSeamfulCubeMapEmulation.enabled)
4125     {
4126         return false;
4127     }
4128 
4129     return true;
4130 }
4131 
shouldUseOldRewriteStructSamplers() const4132 bool ContextVk::shouldUseOldRewriteStructSamplers() const
4133 {
4134     return mRenderer->getFeatures().forceOldRewriteStructSamplers.enabled;
4135 }
4136 
onBufferRead(VkAccessFlags readAccessType,vk::BufferHelper * buffer)4137 angle::Result ContextVk::onBufferRead(VkAccessFlags readAccessType, vk::BufferHelper *buffer)
4138 {
4139     ANGLE_TRY(endRenderPass());
4140 
4141     if (!buffer->canAccumulateRead(this, readAccessType))
4142     {
4143         flushOutsideRenderPassCommands();
4144     }
4145 
4146     mOutsideRenderPassCommands.bufferRead(&mResourceUseList, readAccessType, buffer);
4147 
4148     return angle::Result::Continue;
4149 }
4150 
onBufferWrite(VkAccessFlags writeAccessType,vk::BufferHelper * buffer)4151 angle::Result ContextVk::onBufferWrite(VkAccessFlags writeAccessType, vk::BufferHelper *buffer)
4152 {
4153     ANGLE_TRY(endRenderPass());
4154 
4155     if (!buffer->canAccumulateWrite(this, writeAccessType))
4156     {
4157         flushOutsideRenderPassCommands();
4158     }
4159 
4160     mOutsideRenderPassCommands.bufferWrite(&mResourceUseList, writeAccessType, buffer);
4161 
4162     return angle::Result::Continue;
4163 }
4164 
onImageRead(VkImageAspectFlags aspectFlags,vk::ImageLayout imageLayout,vk::ImageHelper * image)4165 angle::Result ContextVk::onImageRead(VkImageAspectFlags aspectFlags,
4166                                      vk::ImageLayout imageLayout,
4167                                      vk::ImageHelper *image)
4168 {
4169     ANGLE_TRY(endRenderPass());
4170 
4171     if (image->isLayoutChangeNecessary(imageLayout))
4172     {
4173         vk::CommandBuffer *commandBuffer;
4174         ANGLE_TRY(endRenderPassAndGetCommandBuffer(&commandBuffer));
4175         image->changeLayout(aspectFlags, imageLayout, commandBuffer);
4176     }
4177     image->retain(&mResourceUseList);
4178     return angle::Result::Continue;
4179 }
4180 
onImageWrite(VkImageAspectFlags aspectFlags,vk::ImageLayout imageLayout,vk::ImageHelper * image)4181 angle::Result ContextVk::onImageWrite(VkImageAspectFlags aspectFlags,
4182                                       vk::ImageLayout imageLayout,
4183                                       vk::ImageHelper *image)
4184 {
4185     ANGLE_TRY(endRenderPass());
4186 
4187     // Barriers are always required for image writes.
4188     ASSERT(image->isLayoutChangeNecessary(imageLayout));
4189 
4190     vk::CommandBuffer *commandBuffer;
4191     ANGLE_TRY(endRenderPassAndGetCommandBuffer(&commandBuffer));
4192 
4193     image->changeLayout(aspectFlags, imageLayout, commandBuffer);
4194     image->retain(&mResourceUseList);
4195 
4196     return angle::Result::Continue;
4197 }
4198 
flushAndBeginRenderPass(const vk::Framebuffer & framebuffer,const gl::Rectangle & renderArea,const vk::RenderPassDesc & renderPassDesc,const vk::AttachmentOpsArray & renderPassAttachmentOps,const std::vector<VkClearValue> & clearValues,vk::CommandBuffer ** commandBufferOut)4199 angle::Result ContextVk::flushAndBeginRenderPass(
4200     const vk::Framebuffer &framebuffer,
4201     const gl::Rectangle &renderArea,
4202     const vk::RenderPassDesc &renderPassDesc,
4203     const vk::AttachmentOpsArray &renderPassAttachmentOps,
4204     const std::vector<VkClearValue> &clearValues,
4205     vk::CommandBuffer **commandBufferOut)
4206 {
4207     vk::PrimaryCommandBuffer *primary;
4208     ANGLE_TRY(flushAndGetPrimaryCommandBuffer(&primary));
4209 
4210     gl::Rectangle rotatedRenderArea = renderArea;
4211     if (isRotatedAspectRatioForDrawFBO())
4212     {
4213         // The surface is rotated 90/270 degrees.  This changes the aspect ratio of
4214         // the surface.  Swap the width and height of the renderArea.
4215         // TODO(ianelliott): handle small viewport/scissor cases.  http://anglebug.com/4431
4216         std::swap(rotatedRenderArea.width, rotatedRenderArea.height);
4217     }
4218 
4219     mRenderPassCommands.beginRenderPass(framebuffer, rotatedRenderArea, renderPassDesc,
4220                                         renderPassAttachmentOps, clearValues, commandBufferOut);
4221     return angle::Result::Continue;
4222 }
4223 
startRenderPass(gl::Rectangle renderArea)4224 ANGLE_INLINE angle::Result ContextVk::startRenderPass(gl::Rectangle renderArea)
4225 {
4226     mGraphicsDirtyBits |= mNewGraphicsCommandBufferDirtyBits;
4227     ANGLE_TRY(mDrawFramebuffer->startNewRenderPass(this, renderArea, &mRenderPassCommandBuffer));
4228     if (mActiveQueryAnySamples)
4229     {
4230         mActiveQueryAnySamples->getQueryHelper()->beginOcclusionQuery(this, &mPrimaryCommands,
4231                                                                       mRenderPassCommandBuffer);
4232     }
4233     if (mActiveQueryAnySamplesConservative)
4234     {
4235         mActiveQueryAnySamplesConservative->getQueryHelper()->beginOcclusionQuery(
4236             this, &mPrimaryCommands, mRenderPassCommandBuffer);
4237     }
4238     return angle::Result::Continue;
4239 }
4240 
endRenderPass()4241 angle::Result ContextVk::endRenderPass()
4242 {
4243     if (mRenderPassCommands.empty())
4244     {
4245         onRenderPassFinished();
4246         return angle::Result::Continue;
4247     }
4248 
4249     if (mActiveQueryAnySamples)
4250     {
4251         mActiveQueryAnySamples->getQueryHelper()->endOcclusionQuery(this, mRenderPassCommandBuffer);
4252         ANGLE_TRY(mActiveQueryAnySamples->stashQueryHelper(this));
4253     }
4254     if (mActiveQueryAnySamplesConservative)
4255     {
4256         mActiveQueryAnySamplesConservative->getQueryHelper()->endOcclusionQuery(
4257             this, mRenderPassCommandBuffer);
4258         ANGLE_TRY(mActiveQueryAnySamplesConservative->stashQueryHelper(this));
4259     }
4260 
4261     onRenderPassFinished();
4262 
4263     if (mGpuEventsEnabled)
4264     {
4265         mRenderPassCounter++;
4266 
4267         EventName eventName = GetTraceEventName("RP", mRenderPassCounter);
4268         ANGLE_TRY(traceGpuEvent(&mPrimaryCommands, TRACE_EVENT_PHASE_BEGIN, eventName));
4269     }
4270 
4271     mRenderPassCommands.pauseTransformFeedbackIfStarted();
4272 
4273     ANGLE_TRY(mRenderPassCommands.flushToPrimary(this, &mPrimaryCommands));
4274 
4275     if (mGpuEventsEnabled)
4276     {
4277         EventName eventName = GetTraceEventName("RP", mRenderPassCounter);
4278         ANGLE_TRY(traceGpuEvent(&mPrimaryCommands, TRACE_EVENT_PHASE_END, eventName));
4279     }
4280 
4281     return angle::Result::Continue;
4282 }
4283 
onRenderPassImageWrite(VkImageAspectFlags aspectFlags,vk::ImageLayout imageLayout,vk::ImageHelper * image)4284 void ContextVk::onRenderPassImageWrite(VkImageAspectFlags aspectFlags,
4285                                        vk::ImageLayout imageLayout,
4286                                        vk::ImageHelper *image)
4287 {
4288     mRenderPassCommands.imageWrite(&mResourceUseList, aspectFlags, imageLayout, image);
4289 }
4290 
syncExternalMemory()4291 angle::Result ContextVk::syncExternalMemory()
4292 {
4293     vk::CommandBuffer *commandBuffer;
4294     ANGLE_TRY(endRenderPassAndGetCommandBuffer(&commandBuffer));
4295 
4296     VkMemoryBarrier memoryBarrier = {};
4297     memoryBarrier.sType           = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
4298     memoryBarrier.srcAccessMask   = VK_ACCESS_MEMORY_WRITE_BIT;
4299     memoryBarrier.dstAccessMask   = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
4300 
4301     commandBuffer->memoryBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
4302                                  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, &memoryBarrier);
4303     return angle::Result::Continue;
4304 }
4305 
addCommandBufferDiagnostics(const std::string & commandBufferDiagnostics)4306 void ContextVk::addCommandBufferDiagnostics(const std::string &commandBufferDiagnostics)
4307 {
4308     mCommandBufferDiagnostics.push_back(commandBufferDiagnostics);
4309 }
4310 
dumpCommandStreamDiagnostics()4311 void ContextVk::dumpCommandStreamDiagnostics()
4312 {
4313     std::ostream &out = std::cout;
4314 
4315     if (mCommandBufferDiagnostics.empty())
4316         return;
4317 
4318     out << "digraph {\n"
4319         << "  node [shape=plaintext fontname=\"Consolas\"]\n";
4320 
4321     for (size_t index = 0; index < mCommandBufferDiagnostics.size(); ++index)
4322     {
4323         const std::string &payload = mCommandBufferDiagnostics[index];
4324         out << "  cb" << index << " [label =\"" << payload << "\"];\n";
4325     }
4326 
4327     for (size_t index = 0; index < mCommandBufferDiagnostics.size() - 1; ++index)
4328     {
4329         out << "  cb" << index << " -> cb" << index + 1 << "\n";
4330     }
4331 
4332     mCommandBufferDiagnostics.clear();
4333 
4334     out << "}\n";
4335 }
4336 
initIndexTypeMap()4337 void ContextVk::initIndexTypeMap()
4338 {
4339     // Init gles-vulkan index type map
4340     mIndexTypeMap[gl::DrawElementsType::UnsignedByte] =
4341         mRenderer->getFeatures().supportsIndexTypeUint8.enabled ? VK_INDEX_TYPE_UINT8_EXT
4342                                                                 : VK_INDEX_TYPE_UINT16;
4343     mIndexTypeMap[gl::DrawElementsType::UnsignedShort] = VK_INDEX_TYPE_UINT16;
4344     mIndexTypeMap[gl::DrawElementsType::UnsignedInt]   = VK_INDEX_TYPE_UINT32;
4345 }
4346 
getVkIndexType(gl::DrawElementsType glIndexType) const4347 VkIndexType ContextVk::getVkIndexType(gl::DrawElementsType glIndexType) const
4348 {
4349     return mIndexTypeMap[glIndexType];
4350 }
4351 
getVkIndexTypeSize(gl::DrawElementsType glIndexType) const4352 size_t ContextVk::getVkIndexTypeSize(gl::DrawElementsType glIndexType) const
4353 {
4354     gl::DrawElementsType elementsType = shouldConvertUint8VkIndexType(glIndexType)
4355                                             ? gl::DrawElementsType::UnsignedShort
4356                                             : glIndexType;
4357     ASSERT(elementsType < gl::DrawElementsType::EnumCount);
4358 
4359     // Use GetDrawElementsTypeSize() to get the size
4360     return static_cast<size_t>(gl::GetDrawElementsTypeSize(elementsType));
4361 }
4362 
shouldConvertUint8VkIndexType(gl::DrawElementsType glIndexType) const4363 bool ContextVk::shouldConvertUint8VkIndexType(gl::DrawElementsType glIndexType) const
4364 {
4365     return (glIndexType == gl::DrawElementsType::UnsignedByte &&
4366             !mRenderer->getFeatures().supportsIndexTypeUint8.enabled);
4367 }
4368 
flushOutsideRenderPassCommands()4369 void ContextVk::flushOutsideRenderPassCommands()
4370 {
4371     if (!mOutsideRenderPassCommands.empty())
4372     {
4373         mOutsideRenderPassCommands.flushToPrimary(this, &mPrimaryCommands);
4374         mHasPrimaryCommands = true;
4375     }
4376 }
4377 
beginOcclusionQuery(QueryVk * queryVk)4378 void ContextVk::beginOcclusionQuery(QueryVk *queryVk)
4379 {
4380     // To avoid complexity, we always start and end occlusion query inside renderpass. if renderpass
4381     // not yet started, we just remember it and defer the start call.
4382     if (mRenderPassCommands.started())
4383     {
4384         queryVk->getQueryHelper()->beginOcclusionQuery(this, &mPrimaryCommands,
4385                                                        mRenderPassCommandBuffer);
4386     }
4387     if (queryVk->isAnySamplesQuery())
4388     {
4389         ASSERT(mActiveQueryAnySamples == nullptr);
4390         mActiveQueryAnySamples = queryVk;
4391     }
4392     else if (queryVk->isAnySamplesConservativeQuery())
4393     {
4394         ASSERT(mActiveQueryAnySamplesConservative == nullptr);
4395         mActiveQueryAnySamplesConservative = queryVk;
4396     }
4397     else
4398     {
4399         UNREACHABLE();
4400     }
4401 }
4402 
endOcclusionQuery(QueryVk * queryVk)4403 void ContextVk::endOcclusionQuery(QueryVk *queryVk)
4404 {
4405     if (mRenderPassCommands.started())
4406     {
4407         queryVk->getQueryHelper()->endOcclusionQuery(this, mRenderPassCommandBuffer);
4408     }
4409     if (queryVk->isAnySamplesQuery())
4410     {
4411         ASSERT(mActiveQueryAnySamples == queryVk);
4412         mActiveQueryAnySamples = nullptr;
4413     }
4414     else if (queryVk->isAnySamplesConservativeQuery())
4415     {
4416         ASSERT(mActiveQueryAnySamplesConservative == queryVk);
4417         mActiveQueryAnySamplesConservative = nullptr;
4418     }
4419     else
4420     {
4421         UNREACHABLE();
4422     }
4423 }
4424 
isRobustResourceInitEnabled() const4425 bool ContextVk::isRobustResourceInitEnabled() const
4426 {
4427     return mState.isRobustResourceInitEnabled();
4428 }
4429 
CommandBufferHelper()4430 CommandBufferHelper::CommandBufferHelper()
4431     : mImageBarrierSrcStageMask(0),
4432       mImageBarrierDstStageMask(0),
4433       mGlobalMemoryBarrierSrcAccess(0),
4434       mGlobalMemoryBarrierDstAccess(0),
4435       mGlobalMemoryBarrierStages(0)
4436 {}
4437 
4438 CommandBufferHelper::~CommandBufferHelper() = default;
4439 
bufferRead(vk::ResourceUseList * resourceUseList,VkAccessFlags readAccessType,vk::BufferHelper * buffer)4440 void CommandBufferHelper::bufferRead(vk::ResourceUseList *resourceUseList,
4441                                      VkAccessFlags readAccessType,
4442                                      vk::BufferHelper *buffer)
4443 {
4444     buffer->retain(resourceUseList);
4445     buffer->updateReadBarrier(readAccessType, &mGlobalMemoryBarrierSrcAccess,
4446                               &mGlobalMemoryBarrierDstAccess);
4447     mGlobalMemoryBarrierStages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
4448 }
4449 
bufferWrite(vk::ResourceUseList * resourceUseList,VkAccessFlags writeAccessType,vk::BufferHelper * buffer)4450 void CommandBufferHelper::bufferWrite(vk::ResourceUseList *resourceUseList,
4451                                       VkAccessFlags writeAccessType,
4452                                       vk::BufferHelper *buffer)
4453 {
4454     buffer->retain(resourceUseList);
4455     buffer->updateWriteBarrier(writeAccessType, &mGlobalMemoryBarrierSrcAccess,
4456                                &mGlobalMemoryBarrierDstAccess);
4457     mGlobalMemoryBarrierStages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
4458 }
4459 
imageBarrier(VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,const VkImageMemoryBarrier & imageMemoryBarrier)4460 void CommandBufferHelper::imageBarrier(VkPipelineStageFlags srcStageMask,
4461                                        VkPipelineStageFlags dstStageMask,
4462                                        const VkImageMemoryBarrier &imageMemoryBarrier)
4463 {
4464     ASSERT(imageMemoryBarrier.pNext == nullptr);
4465     mImageBarrierSrcStageMask |= srcStageMask;
4466     mImageBarrierDstStageMask |= dstStageMask;
4467     mImageMemoryBarriers.push_back(imageMemoryBarrier);
4468 }
4469 
imageRead(vk::ResourceUseList * resourceUseList,VkImageAspectFlags aspectFlags,vk::ImageLayout imageLayout,vk::ImageHelper * image)4470 void CommandBufferHelper::imageRead(vk::ResourceUseList *resourceUseList,
4471                                     VkImageAspectFlags aspectFlags,
4472                                     vk::ImageLayout imageLayout,
4473                                     vk::ImageHelper *image)
4474 {
4475     image->retain(resourceUseList);
4476     if (image->isLayoutChangeNecessary(imageLayout))
4477     {
4478         image->changeLayout(aspectFlags, imageLayout, this);
4479     }
4480 }
4481 
imageWrite(vk::ResourceUseList * resourceUseList,VkImageAspectFlags aspectFlags,vk::ImageLayout imageLayout,vk::ImageHelper * image)4482 void CommandBufferHelper::imageWrite(vk::ResourceUseList *resourceUseList,
4483                                      VkImageAspectFlags aspectFlags,
4484                                      vk::ImageLayout imageLayout,
4485                                      vk::ImageHelper *image)
4486 {
4487     image->retain(resourceUseList);
4488     image->changeLayout(aspectFlags, imageLayout, this);
4489 }
4490 
executeBarriers(vk::PrimaryCommandBuffer * primary)4491 void CommandBufferHelper::executeBarriers(vk::PrimaryCommandBuffer *primary)
4492 {
4493     if (mImageMemoryBarriers.empty() && mGlobalMemoryBarrierSrcAccess == 0)
4494     {
4495         return;
4496     }
4497 
4498     VkPipelineStageFlags srcStages = 0;
4499     VkPipelineStageFlags dstStages = 0;
4500 
4501     VkMemoryBarrier memoryBarrier = {};
4502     uint32_t memoryBarrierCount   = 0;
4503 
4504     if (mGlobalMemoryBarrierSrcAccess != 0)
4505     {
4506         memoryBarrier.sType         = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
4507         memoryBarrier.srcAccessMask = mGlobalMemoryBarrierSrcAccess;
4508         memoryBarrier.dstAccessMask = mGlobalMemoryBarrierDstAccess;
4509 
4510         memoryBarrierCount++;
4511         srcStages |= mGlobalMemoryBarrierStages;
4512         dstStages |= mGlobalMemoryBarrierStages;
4513 
4514         mGlobalMemoryBarrierSrcAccess = 0;
4515         mGlobalMemoryBarrierDstAccess = 0;
4516         mGlobalMemoryBarrierStages    = 0;
4517     }
4518 
4519     srcStages |= mImageBarrierSrcStageMask;
4520     dstStages |= mImageBarrierDstStageMask;
4521     primary->pipelineBarrier(srcStages, dstStages, 0, memoryBarrierCount, &memoryBarrier, 0,
4522                              nullptr, static_cast<uint32_t>(mImageMemoryBarriers.size()),
4523                              mImageMemoryBarriers.data());
4524     mImageMemoryBarriers.clear();
4525     mImageBarrierSrcStageMask = 0;
4526     mImageBarrierDstStageMask = 0;
4527 }
4528 
4529 OutsideRenderPassCommandBuffer::OutsideRenderPassCommandBuffer() = default;
4530 
4531 OutsideRenderPassCommandBuffer::~OutsideRenderPassCommandBuffer() = default;
4532 
flushToPrimary(ContextVk * contextVk,vk::PrimaryCommandBuffer * primary)4533 void OutsideRenderPassCommandBuffer::flushToPrimary(ContextVk *contextVk,
4534                                                     vk::PrimaryCommandBuffer *primary)
4535 {
4536     if (empty())
4537         return;
4538 
4539     if (kEnableCommandStreamDiagnostics)
4540     {
4541         std::ostringstream out;
4542         if (mGlobalMemoryBarrierSrcAccess != 0 || mGlobalMemoryBarrierDstAccess != 0)
4543         {
4544             out << "Memory Barrier Src: 0x" << std::hex << mGlobalMemoryBarrierSrcAccess
4545                 << " &rarr; Dst: 0x" << std::hex << mGlobalMemoryBarrierDstAccess << "\\l";
4546         }
4547 
4548         out << mCommandBuffer.dumpCommands("\\l");
4549         contextVk->addCommandBufferDiagnostics(out.str());
4550     }
4551 
4552     executeBarriers(primary);
4553     mCommandBuffer.executeCommands(primary->getHandle());
4554 
4555     // Restart secondary buffer.
4556     reset();
4557 }
4558 
reset()4559 void OutsideRenderPassCommandBuffer::reset()
4560 {
4561     mCommandBuffer.reset();
4562 }
4563 
RenderPassCommandBuffer()4564 RenderPassCommandBuffer::RenderPassCommandBuffer()
4565     : mCounter(0),
4566       mClearValues{},
4567       mRenderPassStarted(false),
4568       mTransformFeedbackCounterBuffers{},
4569       mValidTransformFeedbackBufferCount(0),
4570       mRebindTransformFeedbackBuffers(false)
4571 {}
4572 
~RenderPassCommandBuffer()4573 RenderPassCommandBuffer::~RenderPassCommandBuffer()
4574 {
4575     mFramebuffer.setHandle(VK_NULL_HANDLE);
4576 }
4577 
initialize(angle::PoolAllocator * poolAllocator)4578 void RenderPassCommandBuffer::initialize(angle::PoolAllocator *poolAllocator)
4579 {
4580     mCommandBuffer.initialize(poolAllocator);
4581 }
4582 
beginRenderPass(const vk::Framebuffer & framebuffer,const gl::Rectangle & renderArea,const vk::RenderPassDesc & renderPassDesc,const vk::AttachmentOpsArray & renderPassAttachmentOps,const std::vector<VkClearValue> & clearValues,vk::CommandBuffer ** commandBufferOut)4583 void RenderPassCommandBuffer::beginRenderPass(const vk::Framebuffer &framebuffer,
4584                                               const gl::Rectangle &renderArea,
4585                                               const vk::RenderPassDesc &renderPassDesc,
4586                                               const vk::AttachmentOpsArray &renderPassAttachmentOps,
4587                                               const std::vector<VkClearValue> &clearValues,
4588                                               vk::CommandBuffer **commandBufferOut)
4589 {
4590     ASSERT(empty());
4591 
4592     mRenderPassDesc = renderPassDesc;
4593     mAttachmentOps  = renderPassAttachmentOps;
4594     mFramebuffer.setHandle(framebuffer.getHandle());
4595     mRenderArea = renderArea;
4596     std::copy(clearValues.begin(), clearValues.end(), mClearValues.begin());
4597 
4598     *commandBufferOut = &mCommandBuffer;
4599 
4600     mRenderPassStarted = true;
4601     mCounter++;
4602 }
4603 
beginTransformFeedback(size_t validBufferCount,const VkBuffer * counterBuffers,bool rebindBuffer)4604 void RenderPassCommandBuffer::beginTransformFeedback(size_t validBufferCount,
4605                                                      const VkBuffer *counterBuffers,
4606                                                      bool rebindBuffer)
4607 {
4608     mValidTransformFeedbackBufferCount = static_cast<uint32_t>(validBufferCount);
4609     mRebindTransformFeedbackBuffers    = rebindBuffer;
4610 
4611     for (size_t index = 0; index < validBufferCount; index++)
4612     {
4613         mTransformFeedbackCounterBuffers[index] = counterBuffers[index];
4614     }
4615 }
4616 
flushToPrimary(ContextVk * contextVk,vk::PrimaryCommandBuffer * primary)4617 angle::Result RenderPassCommandBuffer::flushToPrimary(ContextVk *contextVk,
4618                                                       vk::PrimaryCommandBuffer *primary)
4619 {
4620     if (empty())
4621         return angle::Result::Continue;
4622 
4623     if (kEnableCommandStreamDiagnostics)
4624     {
4625         addRenderPassCommandDiagnostics(contextVk);
4626     }
4627 
4628     executeBarriers(primary);
4629 
4630     // Pull a RenderPass from the cache.
4631     RenderPassCache &renderPassCache = contextVk->getRenderPassCache();
4632     Serial serial                    = contextVk->getCurrentQueueSerial();
4633 
4634     vk::RenderPass *renderPass = nullptr;
4635     ANGLE_TRY(renderPassCache.getRenderPassWithOps(contextVk, serial, mRenderPassDesc,
4636                                                    mAttachmentOps, &renderPass));
4637 
4638     VkRenderPassBeginInfo beginInfo    = {};
4639     beginInfo.sType                    = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
4640     beginInfo.renderPass               = renderPass->getHandle();
4641     beginInfo.framebuffer              = mFramebuffer.getHandle();
4642     beginInfo.renderArea.offset.x      = static_cast<uint32_t>(mRenderArea.x);
4643     beginInfo.renderArea.offset.y      = static_cast<uint32_t>(mRenderArea.y);
4644     beginInfo.renderArea.extent.width  = static_cast<uint32_t>(mRenderArea.width);
4645     beginInfo.renderArea.extent.height = static_cast<uint32_t>(mRenderArea.height);
4646     beginInfo.clearValueCount          = static_cast<uint32_t>(mRenderPassDesc.attachmentCount());
4647     beginInfo.pClearValues             = mClearValues.data();
4648 
4649     // Run commands inside the RenderPass.
4650     primary->beginRenderPass(beginInfo, VK_SUBPASS_CONTENTS_INLINE);
4651 
4652     if (mValidTransformFeedbackBufferCount == 0)
4653     {
4654         mCommandBuffer.executeCommands(primary->getHandle());
4655         primary->endRenderPass();
4656     }
4657     else
4658     {
4659         mCommandBuffer.executeCommands(primary->getHandle());
4660         primary->endRenderPass();
4661 
4662         // Would be better to accumulate this barrier using the command APIs.
4663         // TODO: Clean thus up before we close http://anglebug.com/3206
4664         VkBufferMemoryBarrier bufferBarrier = {};
4665         bufferBarrier.sType                 = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
4666         bufferBarrier.pNext                 = nullptr;
4667         bufferBarrier.srcAccessMask         = VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT;
4668         bufferBarrier.dstAccessMask         = VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT;
4669         bufferBarrier.srcQueueFamilyIndex   = VK_QUEUE_FAMILY_IGNORED;
4670         bufferBarrier.dstQueueFamilyIndex   = VK_QUEUE_FAMILY_IGNORED;
4671         bufferBarrier.buffer                = mTransformFeedbackCounterBuffers[0];
4672         bufferBarrier.offset                = 0;
4673         bufferBarrier.size                  = VK_WHOLE_SIZE;
4674 
4675         primary->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
4676                                  VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, 0u, 0u, nullptr, 1u,
4677                                  &bufferBarrier, 0u, nullptr);
4678     }
4679 
4680     // Restart the command buffer.
4681     reset();
4682 
4683     return angle::Result::Continue;
4684 }
4685 
addRenderPassCommandDiagnostics(ContextVk * contextVk)4686 void RenderPassCommandBuffer::addRenderPassCommandDiagnostics(ContextVk *contextVk)
4687 {
4688     std::ostringstream out;
4689     if (mGlobalMemoryBarrierSrcAccess != 0 || mGlobalMemoryBarrierDstAccess != 0)
4690     {
4691         out << "Memory Barrier Src: 0x" << std::hex << mGlobalMemoryBarrierSrcAccess
4692             << " &rarr; Dst: 0x" << std::hex << mGlobalMemoryBarrierDstAccess << "\\l";
4693     }
4694 
4695     size_t attachmentCount             = mRenderPassDesc.attachmentCount();
4696     size_t depthStencilAttachmentCount = mRenderPassDesc.hasDepthStencilAttachment();
4697     size_t colorAttachmentCount        = attachmentCount - depthStencilAttachmentCount;
4698 
4699     std::string loadOps, storeOps;
4700 
4701     if (colorAttachmentCount > 0)
4702     {
4703         loadOps += " Color: ";
4704         storeOps += " Color: ";
4705 
4706         for (size_t i = 0; i < colorAttachmentCount; ++i)
4707         {
4708             loadOps += GetLoadOpShorthand(mAttachmentOps[i].loadOp);
4709             storeOps += GetStoreOpShorthand(mAttachmentOps[i].storeOp);
4710         }
4711     }
4712 
4713     if (depthStencilAttachmentCount > 0)
4714     {
4715         ASSERT(depthStencilAttachmentCount == 1);
4716 
4717         loadOps += " Depth/Stencil: ";
4718         storeOps += " Depth/Stencil: ";
4719         size_t dsIndex = colorAttachmentCount;
4720 
4721         loadOps += GetLoadOpShorthand(mAttachmentOps[dsIndex].loadOp);
4722         loadOps += GetLoadOpShorthand(mAttachmentOps[dsIndex].stencilLoadOp);
4723 
4724         storeOps += GetStoreOpShorthand(mAttachmentOps[dsIndex].storeOp);
4725         storeOps += GetStoreOpShorthand(mAttachmentOps[dsIndex].stencilStoreOp);
4726     }
4727 
4728     if (attachmentCount > 0)
4729     {
4730         out << "LoadOp:  " << loadOps << "\\l";
4731         out << "StoreOp: " << storeOps << "\\l";
4732     }
4733 
4734     out << mCommandBuffer.dumpCommands("\\l");
4735     contextVk->addCommandBufferDiagnostics(out.str());
4736 }
4737 
reset()4738 void RenderPassCommandBuffer::reset()
4739 {
4740     mCommandBuffer.reset();
4741     mRenderPassStarted                 = false;
4742     mValidTransformFeedbackBufferCount = 0;
4743     mRebindTransformFeedbackBuffers    = false;
4744 }
4745 
resumeTransformFeedbackIfStarted()4746 void RenderPassCommandBuffer::resumeTransformFeedbackIfStarted()
4747 {
4748     if (mValidTransformFeedbackBufferCount == 0)
4749     {
4750         return;
4751     }
4752 
4753     uint32_t numCounterBuffers =
4754         mRebindTransformFeedbackBuffers ? 0 : mValidTransformFeedbackBufferCount;
4755 
4756     mRebindTransformFeedbackBuffers = false;
4757 
4758     mCommandBuffer.beginTransformFeedback(numCounterBuffers,
4759                                           mTransformFeedbackCounterBuffers.data());
4760 }
4761 
pauseTransformFeedbackIfStarted()4762 void RenderPassCommandBuffer::pauseTransformFeedbackIfStarted()
4763 {
4764     if (mValidTransformFeedbackBufferCount == 0)
4765     {
4766         return;
4767     }
4768 
4769     mCommandBuffer.endTransformFeedback(mValidTransformFeedbackBufferCount,
4770                                         mTransformFeedbackCounterBuffers.data());
4771 }
4772 
4773 }  // namespace rx
4774