• 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/CommandGraph.h"
23 #include "libANGLE/renderer/vulkan/CompilerVk.h"
24 #include "libANGLE/renderer/vulkan/FenceNVVk.h"
25 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
26 #include "libANGLE/renderer/vulkan/MemoryObjectVk.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 namespace rx
44 {
45 
46 namespace
47 {
48 // For shader uniforms such as gl_DepthRange and the viewport size.
49 struct GraphicsDriverUniforms
50 {
51     std::array<float, 4> viewport;
52 
53     float halfRenderAreaHeight;
54     float viewportYScale;
55     float negViewportYScale;
56     uint32_t xfbActiveUnpaused;
57 
58     std::array<int32_t, 4> xfbBufferOffsets;
59 
60     // .xy contain packed 8-bit values for atomic counter buffer offsets.  These offsets are
61     // within Vulkan's minStorageBufferOffsetAlignment limit and are used to support unaligned
62     // offsets allowed in GL.
63     //
64     // .zw are unused.
65     std::array<uint32_t, 4> acbBufferOffsets;
66 
67     // We'll use x, y, z for near / far / diff respectively.
68     std::array<float, 4> depthRange;
69 };
70 
71 struct ComputeDriverUniforms
72 {
73     // Atomic counter buffer offsets with the same layout as in GraphicsDriverUniforms.
74     std::array<uint32_t, 4> acbBufferOffsets;
75 };
76 
DefaultGLErrorCode(VkResult result)77 GLenum DefaultGLErrorCode(VkResult result)
78 {
79     switch (result)
80     {
81         case VK_ERROR_OUT_OF_HOST_MEMORY:
82         case VK_ERROR_OUT_OF_DEVICE_MEMORY:
83         case VK_ERROR_TOO_MANY_OBJECTS:
84             return GL_OUT_OF_MEMORY;
85         default:
86             return GL_INVALID_OPERATION;
87     }
88 }
89 
90 constexpr VkColorComponentFlags kAllColorChannelsMask =
91     (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
92      VK_COLOR_COMPONENT_A_BIT);
93 
94 constexpr VkBufferUsageFlags kVertexBufferUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
95 constexpr size_t kDefaultValueSize              = sizeof(gl::VertexAttribCurrentValueData::Values);
96 constexpr size_t kDefaultBufferSize             = kDefaultValueSize * 16;
97 constexpr size_t kDefaultPoolAllocatorPageSize  = 16 * 1024;
98 constexpr size_t kDriverUniformsAllocatorPageSize = 4 * 1024;
99 
100 // Wait a maximum of 10s.  If that times out, we declare it a failure.
101 constexpr uint64_t kMaxFenceWaitTimeNs = 10'000'000'000llu;
102 
103 constexpr size_t kInFlightCommandsLimit = 100u;
104 
105 // Initially dumping the command graphs is disabled.
106 constexpr bool kEnableCommandGraphDiagnostics = false;
107 
108 // Used as fallback serial for null sampler objects
109 constexpr Serial kZeroSerial = Serial();
110 
InitializeSubmitInfo(VkSubmitInfo * submitInfo,const vk::PrimaryCommandBuffer & commandBuffer,const std::vector<VkSemaphore> & waitSemaphores,std::vector<VkPipelineStageFlags> * waitSemaphoreStageMasks,const vk::Semaphore * signalSemaphore)111 void InitializeSubmitInfo(VkSubmitInfo *submitInfo,
112                           const vk::PrimaryCommandBuffer &commandBuffer,
113                           const std::vector<VkSemaphore> &waitSemaphores,
114                           std::vector<VkPipelineStageFlags> *waitSemaphoreStageMasks,
115                           const vk::Semaphore *signalSemaphore)
116 {
117     // Verify that the submitInfo has been zero'd out.
118     ASSERT(submitInfo->signalSemaphoreCount == 0);
119 
120     submitInfo->sType              = VK_STRUCTURE_TYPE_SUBMIT_INFO;
121     submitInfo->commandBufferCount = commandBuffer.valid() ? 1 : 0;
122     submitInfo->pCommandBuffers    = commandBuffer.ptr();
123 
124     if (waitSemaphoreStageMasks->size() < waitSemaphores.size())
125     {
126         waitSemaphoreStageMasks->resize(waitSemaphores.size(),
127                                         VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
128     }
129 
130     submitInfo->waitSemaphoreCount = static_cast<uint32_t>(waitSemaphores.size());
131     submitInfo->pWaitSemaphores    = waitSemaphores.data();
132     submitInfo->pWaitDstStageMask  = waitSemaphoreStageMasks->data();
133 
134     if (signalSemaphore)
135     {
136         submitInfo->signalSemaphoreCount = 1;
137         submitInfo->pSignalSemaphores    = signalSemaphore->ptr();
138     }
139 }
140 
GetCoverageSampleCount(const gl::State & glState,FramebufferVk * drawFramebuffer)141 uint32_t GetCoverageSampleCount(const gl::State &glState, FramebufferVk *drawFramebuffer)
142 {
143     if (!glState.isSampleCoverageEnabled())
144     {
145         return 0;
146     }
147 
148     // Get a fraction of the samples based on the coverage parameters.
149     return static_cast<uint32_t>(
150         std::round(glState.getSampleCoverageValue() * drawFramebuffer->getSamples()));
151 }
152 
ApplySampleCoverage(const gl::State & glState,uint32_t coverageSampleCount,uint32_t maskNumber,uint32_t * maskOut)153 void ApplySampleCoverage(const gl::State &glState,
154                          uint32_t coverageSampleCount,
155                          uint32_t maskNumber,
156                          uint32_t *maskOut)
157 {
158     if (!glState.isSampleCoverageEnabled())
159     {
160         return;
161     }
162 
163     uint32_t maskBitOffset = maskNumber * 32;
164     uint32_t coverageMask  = coverageSampleCount >= (maskBitOffset + 32)
165                                 ? std::numeric_limits<uint32_t>::max()
166                                 : (1u << (coverageSampleCount - maskBitOffset)) - 1;
167 
168     if (glState.getSampleCoverageInvert())
169     {
170         coverageMask = ~coverageMask;
171     }
172 
173     *maskOut &= coverageMask;
174 }
175 
176 }  // anonymous namespace
177 
DriverUniformsDescriptorSet()178 ContextVk::DriverUniformsDescriptorSet::DriverUniformsDescriptorSet()
179     : descriptorSet(VK_NULL_HANDLE), dynamicOffset(0)
180 {}
181 
182 ContextVk::DriverUniformsDescriptorSet::~DriverUniformsDescriptorSet() = default;
183 
init(RendererVk * rendererVk)184 void ContextVk::DriverUniformsDescriptorSet::init(RendererVk *rendererVk)
185 {
186     size_t minAlignment = static_cast<size_t>(
187         rendererVk->getPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment);
188     dynamicBuffer.init(rendererVk, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, minAlignment,
189                        kDriverUniformsAllocatorPageSize, true);
190 }
191 
destroy(VkDevice device)192 void ContextVk::DriverUniformsDescriptorSet::destroy(VkDevice device)
193 {
194     descriptorSetLayout.reset();
195     descriptorPoolBinding.reset();
196     dynamicBuffer.destroy(device);
197 }
198 
199 // CommandBatch implementation.
200 ContextVk::CommandBatch::CommandBatch() = default;
201 
202 ContextVk::CommandBatch::~CommandBatch() = default;
203 
CommandBatch(CommandBatch && other)204 ContextVk::CommandBatch::CommandBatch(CommandBatch &&other)
205 {
206     *this = std::move(other);
207 }
208 
operator =(CommandBatch && other)209 ContextVk::CommandBatch &ContextVk::CommandBatch::operator=(CommandBatch &&other)
210 {
211     std::swap(primaryCommands, other.primaryCommands);
212     std::swap(commandPool, other.commandPool);
213     std::swap(fence, other.fence);
214     std::swap(serial, other.serial);
215     return *this;
216 }
217 
destroy(VkDevice device)218 void ContextVk::CommandBatch::destroy(VkDevice device)
219 {
220     primaryCommands.destroy(device);
221     commandPool.destroy(device);
222     fence.reset(device);
223 }
224 
ContextVk(const gl::State & state,gl::ErrorSet * errorSet,RendererVk * renderer)225 ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk *renderer)
226     : ContextImpl(state, errorSet),
227       vk::Context(renderer),
228       mCurrentGraphicsPipeline(nullptr),
229       mCurrentComputePipeline(nullptr),
230       mCurrentDrawMode(gl::PrimitiveMode::InvalidEnum),
231       mCurrentWindowSurface(nullptr),
232       mVertexArray(nullptr),
233       mDrawFramebuffer(nullptr),
234       mProgram(nullptr),
235       mLastIndexBufferOffset(0),
236       mCurrentDrawElementsType(gl::DrawElementsType::InvalidEnum),
237       mXfbBaseVertex(0),
238       mClearColorMask(kAllColorChannelsMask),
239       mFlipYForCurrentSurface(false),
240       mIsAnyHostVisibleBufferWritten(false),
241       mEmulateSeamfulCubeMapSampling(false),
242       mEmulateSeamfulCubeMapSamplingWithSubgroupOps(false),
243       mLastCompletedQueueSerial(renderer->nextSerial()),
244       mCurrentQueueSerial(renderer->nextSerial()),
245       mPoolAllocator(kDefaultPoolAllocatorPageSize, 1),
246       mCommandGraph(kEnableCommandGraphDiagnostics, &mPoolAllocator),
247       mGpuEventsEnabled(false),
248       mGpuClockSync{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()},
249       mGpuEventTimestampOrigin(0)
250 {
251     ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::ContextVk");
252     memset(&mClearColorValue, 0, sizeof(mClearColorValue));
253     memset(&mClearDepthStencilValue, 0, sizeof(mClearDepthStencilValue));
254 
255     mNonIndexedDirtyBitsMask.set();
256     mNonIndexedDirtyBitsMask.reset(DIRTY_BIT_INDEX_BUFFER);
257 
258     mIndexedDirtyBitsMask.set();
259 
260     mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_PIPELINE);
261     mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_TEXTURES);
262     mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
263     mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
264     mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES);
265     mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
266     mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
267 
268     mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_PIPELINE);
269     mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_TEXTURES);
270     mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES);
271     mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
272 
273     mGraphicsDirtyBitHandlers[DIRTY_BIT_DEFAULT_ATTRIBS] =
274         &ContextVk::handleDirtyGraphicsDefaultAttribs;
275     mGraphicsDirtyBitHandlers[DIRTY_BIT_PIPELINE] = &ContextVk::handleDirtyGraphicsPipeline;
276     mGraphicsDirtyBitHandlers[DIRTY_BIT_TEXTURES] = &ContextVk::handleDirtyGraphicsTextures;
277     mGraphicsDirtyBitHandlers[DIRTY_BIT_VERTEX_BUFFERS] =
278         &ContextVk::handleDirtyGraphicsVertexBuffers;
279     mGraphicsDirtyBitHandlers[DIRTY_BIT_INDEX_BUFFER] = &ContextVk::handleDirtyGraphicsIndexBuffer;
280     mGraphicsDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] =
281         &ContextVk::handleDirtyGraphicsDriverUniforms;
282     mGraphicsDirtyBitHandlers[DIRTY_BIT_SHADER_RESOURCES] =
283         &ContextVk::handleDirtyGraphicsShaderResources;
284     mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
285         &ContextVk::handleDirtyGraphicsTransformFeedbackBuffers;
286     mGraphicsDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] =
287         &ContextVk::handleDirtyGraphicsDescriptorSets;
288 
289     mComputeDirtyBitHandlers[DIRTY_BIT_PIPELINE] = &ContextVk::handleDirtyComputePipeline;
290     mComputeDirtyBitHandlers[DIRTY_BIT_TEXTURES] = &ContextVk::handleDirtyComputeTextures;
291     mComputeDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] =
292         &ContextVk::handleDirtyComputeDriverUniforms;
293     mComputeDirtyBitHandlers[DIRTY_BIT_SHADER_RESOURCES] =
294         &ContextVk::handleDirtyComputeShaderResources;
295     mComputeDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] =
296         &ContextVk::handleDirtyComputeDescriptorSets;
297 
298     mGraphicsDirtyBits = mNewGraphicsCommandBufferDirtyBits;
299     mComputeDirtyBits  = mNewComputeCommandBufferDirtyBits;
300 
301     mActiveTextures.fill({nullptr, nullptr});
302 
303     mPipelineDirtyBitsMask.set();
304     mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_TEXTURE_BINDINGS);
305 }
306 
307 ContextVk::~ContextVk() = default;
308 
onDestroy(const gl::Context * context)309 void ContextVk::onDestroy(const gl::Context *context)
310 {
311     // Force a flush on destroy.
312     (void)finishImpl();
313 
314     VkDevice device = getDevice();
315 
316     mIncompleteTextures.onDestroy(context);
317 
318     for (DriverUniformsDescriptorSet &driverUniforms : mDriverUniforms)
319     {
320         driverUniforms.destroy(device);
321     }
322 
323     mDriverUniformsDescriptorPool.destroy(device);
324 
325     for (vk::DynamicBuffer &defaultBuffer : mDefaultAttribBuffers)
326     {
327         defaultBuffer.destroy(device);
328     }
329 
330     for (vk::DynamicQueryPool &queryPool : mQueryPools)
331     {
332         queryPool.destroy(device);
333     }
334 
335     if (!mInFlightCommands.empty() || !mGarbage.empty())
336     {
337         (void)finishImpl();
338     }
339 
340     mUtils.destroy(device);
341 
342     mRenderPassCache.destroy(device);
343     mSubmitFence.reset(device);
344     mShaderLibrary.destroy(device);
345     mGpuEventQueryPool.destroy(device);
346     mCommandPool.destroy(device);
347 
348     if (ANGLE_LIKELY(!mRenderer->getFeatures().transientCommandBuffer.enabled))
349     {
350         mPrimaryCommandPool.destroy(this);
351     }
352 
353     for (vk::CommandPool &pool : mCommandPoolFreeList)
354     {
355         pool.destroy(device);
356     }
357 }
358 
getIncompleteTexture(const gl::Context * context,gl::TextureType type,gl::Texture ** textureOut)359 angle::Result ContextVk::getIncompleteTexture(const gl::Context *context,
360                                               gl::TextureType type,
361                                               gl::Texture **textureOut)
362 {
363     // At some point, we'll need to support multisample and we'll pass "this" instead of nullptr
364     // and implement the necessary interface.
365     return mIncompleteTextures.getIncompleteTexture(context, type, nullptr, textureOut);
366 }
367 
initialize()368 angle::Result ContextVk::initialize()
369 {
370     ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::initialize");
371 
372     VkDescriptorPoolSize driverSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1};
373     ANGLE_TRY(mDriverUniformsDescriptorPool.init(this, &driverSetSize, 1));
374 
375     ANGLE_TRY(mQueryPools[gl::QueryType::AnySamples].init(this, VK_QUERY_TYPE_OCCLUSION,
376                                                           vk::kDefaultOcclusionQueryPoolSize));
377     ANGLE_TRY(mQueryPools[gl::QueryType::AnySamplesConservative].init(
378         this, VK_QUERY_TYPE_OCCLUSION, vk::kDefaultOcclusionQueryPoolSize));
379     ANGLE_TRY(mQueryPools[gl::QueryType::Timestamp].init(this, VK_QUERY_TYPE_TIMESTAMP,
380                                                          vk::kDefaultTimestampQueryPoolSize));
381     ANGLE_TRY(mQueryPools[gl::QueryType::TimeElapsed].init(this, VK_QUERY_TYPE_TIMESTAMP,
382                                                            vk::kDefaultTimestampQueryPoolSize));
383 
384     // Init driver uniforms and get the descriptor set layouts.
385     constexpr angle::PackedEnumMap<PipelineType, VkShaderStageFlags> kPipelineStages = {
386         {PipelineType::Graphics, VK_SHADER_STAGE_ALL_GRAPHICS},
387         {PipelineType::Compute, VK_SHADER_STAGE_COMPUTE_BIT},
388     };
389     for (PipelineType pipeline : angle::AllEnums<PipelineType>())
390     {
391         mDriverUniforms[pipeline].init(mRenderer);
392 
393         vk::DescriptorSetLayoutDesc desc =
394             getDriverUniformsDescriptorSetDesc(kPipelineStages[pipeline]);
395         ANGLE_TRY(mRenderer->getDescriptorSetLayout(
396             this, desc, &mDriverUniforms[pipeline].descriptorSetLayout));
397     }
398 
399     mGraphicsPipelineDesc.reset(new vk::GraphicsPipelineDesc());
400     mGraphicsPipelineDesc->initDefaults();
401 
402     // Initialize current value/default attribute buffers.
403     for (vk::DynamicBuffer &buffer : mDefaultAttribBuffers)
404     {
405         buffer.init(mRenderer, kVertexBufferUsage, 1, kDefaultBufferSize, true);
406     }
407 
408     // Initialize the command pool now that we know the queue family index.
409     uint32_t queueFamilyIndex = getRenderer()->getQueueFamilyIndex();
410     if (ANGLE_LIKELY(!mRenderer->getFeatures().transientCommandBuffer.enabled))
411     {
412         ANGLE_TRY(mPrimaryCommandPool.init(this, queueFamilyIndex));
413     }
414     else
415     {
416         // Once the transientCommandBuffer issue being resolved, the commandPool will only
417         // used for secondaryBuffer allocation, so we can guard this block of code use macro
418         // ANGLE_USE_CUSTOM_VULKAN_CMD_BUFFERS
419         VkCommandPoolCreateInfo commandPoolInfo = {};
420         commandPoolInfo.sType                   = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
421         commandPoolInfo.flags                   = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
422         commandPoolInfo.queueFamilyIndex        = queueFamilyIndex;
423 
424         ANGLE_VK_TRY(this, mCommandPool.init(getDevice(), commandPoolInfo));
425     }
426 
427 #if ANGLE_ENABLE_VULKAN_GPU_TRACE_EVENTS
428     angle::PlatformMethods *platform = ANGLEPlatformCurrent();
429     ASSERT(platform);
430 
431     // GPU tracing workaround for anglebug.com/2927.  The renderer should not emit gpu events during
432     // platform discovery.
433     const unsigned char *gpuEventsEnabled =
434         platform->getTraceCategoryEnabledFlag(platform, "gpu.angle.gpu");
435     mGpuEventsEnabled = gpuEventsEnabled && *gpuEventsEnabled;
436 #endif
437 
438     if (mGpuEventsEnabled)
439     {
440         // Calculate the difference between CPU and GPU clocks for GPU event reporting.
441         ANGLE_TRY(mGpuEventQueryPool.init(this, VK_QUERY_TYPE_TIMESTAMP,
442                                           vk::kDefaultTimestampQueryPoolSize));
443         ANGLE_TRY(synchronizeCpuGpuTime());
444     }
445 
446     mEmulateSeamfulCubeMapSampling =
447         shouldEmulateSeamfulCubeMapSampling(&mEmulateSeamfulCubeMapSamplingWithSubgroupOps);
448 
449     return angle::Result::Continue;
450 }
451 
flush(const gl::Context * context)452 angle::Result ContextVk::flush(const gl::Context *context)
453 {
454     return flushImpl(nullptr);
455 }
456 
finish(const gl::Context * context)457 angle::Result ContextVk::finish(const gl::Context *context)
458 {
459     return finishImpl();
460 }
461 
setupDraw(const gl::Context * context,gl::PrimitiveMode mode,GLint firstVertex,GLsizei vertexOrIndexCount,GLsizei instanceCount,gl::DrawElementsType indexTypeOrNone,const void * indices,DirtyBits dirtyBitMask,vk::CommandBuffer ** commandBufferOut)462 angle::Result ContextVk::setupDraw(const gl::Context *context,
463                                    gl::PrimitiveMode mode,
464                                    GLint firstVertex,
465                                    GLsizei vertexOrIndexCount,
466                                    GLsizei instanceCount,
467                                    gl::DrawElementsType indexTypeOrNone,
468                                    const void *indices,
469                                    DirtyBits dirtyBitMask,
470                                    vk::CommandBuffer **commandBufferOut)
471 {
472     // Set any dirty bits that depend on draw call parameters or other objects.
473     if (mode != mCurrentDrawMode)
474     {
475         invalidateCurrentGraphicsPipeline();
476         mCurrentDrawMode = mode;
477         mGraphicsPipelineDesc->updateTopology(&mGraphicsPipelineTransition, mCurrentDrawMode);
478     }
479 
480     // Must be called before the command buffer is started. Can call finish.
481     if (context->getStateCache().hasAnyActiveClientAttrib())
482     {
483         ANGLE_TRY(mVertexArray->updateClientAttribs(context, firstVertex, vertexOrIndexCount,
484                                                     instanceCount, indexTypeOrNone, indices));
485         mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
486     }
487 
488     // This could be improved using a dirty bit. But currently it's slower to use a handler
489     // function than an inlined if. We should probably replace the dirty bit dispatch table
490     // with a switch with inlined handler functions.
491     // TODO(jmadill): Use dirty bit. http://anglebug.com/3014
492     if (!mRenderPassCommandBuffer)
493     {
494         mGraphicsDirtyBits |= mNewGraphicsCommandBufferDirtyBits;
495 
496         gl::Rectangle scissoredRenderArea = mDrawFramebuffer->getScissoredRenderArea(this);
497         if (!mDrawFramebuffer->appendToStartedRenderPass(
498                 getCurrentQueueSerial(), scissoredRenderArea, &mRenderPassCommandBuffer))
499         {
500             ANGLE_TRY(mDrawFramebuffer->startNewRenderPass(this, scissoredRenderArea,
501                                                            &mRenderPassCommandBuffer));
502         }
503     }
504 
505     // We keep a local copy of the command buffer. It's possible that some state changes could
506     // trigger a command buffer invalidation. The local copy ensures we retain the reference.
507     // Command buffers are pool allocated and only deleted after submit. Thus we know the
508     // command buffer will still be valid for the duration of this API call.
509     *commandBufferOut = mRenderPassCommandBuffer;
510     ASSERT(*commandBufferOut);
511 
512     if (mProgram->dirtyUniforms())
513     {
514         ANGLE_TRY(mProgram->updateUniforms(this));
515         mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
516     }
517 
518     // Update transform feedback offsets on every draw call.
519     if (mState.isTransformFeedbackActiveUnpaused())
520     {
521         mXfbBaseVertex = firstVertex;
522         invalidateGraphicsDriverUniforms();
523     }
524 
525     DirtyBits dirtyBits = mGraphicsDirtyBits & dirtyBitMask;
526 
527     if (dirtyBits.none())
528         return angle::Result::Continue;
529 
530     // Flush any relevant dirty bits.
531     for (size_t dirtyBit : dirtyBits)
532     {
533         ANGLE_TRY((this->*mGraphicsDirtyBitHandlers[dirtyBit])(context, *commandBufferOut));
534     }
535 
536     mGraphicsDirtyBits &= ~dirtyBitMask;
537 
538     return angle::Result::Continue;
539 }
540 
setupIndexedDraw(const gl::Context * context,gl::PrimitiveMode mode,GLsizei indexCount,GLsizei instanceCount,gl::DrawElementsType indexType,const void * indices,vk::CommandBuffer ** commandBufferOut)541 angle::Result ContextVk::setupIndexedDraw(const gl::Context *context,
542                                           gl::PrimitiveMode mode,
543                                           GLsizei indexCount,
544                                           GLsizei instanceCount,
545                                           gl::DrawElementsType indexType,
546                                           const void *indices,
547                                           vk::CommandBuffer **commandBufferOut)
548 {
549     ASSERT(mode != gl::PrimitiveMode::LineLoop);
550 
551     if (indexType != mCurrentDrawElementsType)
552     {
553         mCurrentDrawElementsType = indexType;
554         setIndexBufferDirty();
555     }
556 
557     const gl::Buffer *elementArrayBuffer = mVertexArray->getState().getElementArrayBuffer();
558     if (!elementArrayBuffer)
559     {
560         mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
561         ANGLE_TRY(mVertexArray->convertIndexBufferCPU(this, indexType, indexCount, indices));
562     }
563     else
564     {
565         if (indices != mLastIndexBufferOffset)
566         {
567             mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
568             mLastIndexBufferOffset = indices;
569             mVertexArray->updateCurrentElementArrayBufferOffset(mLastIndexBufferOffset);
570         }
571 
572         if (indexType == gl::DrawElementsType::UnsignedByte &&
573             mGraphicsDirtyBits[DIRTY_BIT_INDEX_BUFFER])
574         {
575             BufferVk *bufferVk = vk::GetImpl(elementArrayBuffer);
576             ANGLE_TRY(mVertexArray->convertIndexBufferGPU(this, bufferVk, indices));
577         }
578     }
579 
580     return setupDraw(context, mode, 0, indexCount, instanceCount, indexType, indices,
581                      mIndexedDirtyBitsMask, commandBufferOut);
582 }
583 
setupLineLoopDraw(const gl::Context * context,gl::PrimitiveMode mode,GLint firstVertex,GLsizei vertexOrIndexCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,vk::CommandBuffer ** commandBufferOut,uint32_t * numIndicesOut)584 angle::Result ContextVk::setupLineLoopDraw(const gl::Context *context,
585                                            gl::PrimitiveMode mode,
586                                            GLint firstVertex,
587                                            GLsizei vertexOrIndexCount,
588                                            gl::DrawElementsType indexTypeOrInvalid,
589                                            const void *indices,
590                                            vk::CommandBuffer **commandBufferOut,
591                                            uint32_t *numIndicesOut)
592 {
593     ANGLE_TRY(mVertexArray->handleLineLoop(this, firstVertex, vertexOrIndexCount,
594                                            indexTypeOrInvalid, indices, numIndicesOut));
595     setIndexBufferDirty();
596     mCurrentDrawElementsType = indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum
597                                    ? indexTypeOrInvalid
598                                    : gl::DrawElementsType::UnsignedInt;
599     return setupDraw(context, mode, firstVertex, vertexOrIndexCount, 1, indexTypeOrInvalid, indices,
600                      mIndexedDirtyBitsMask, commandBufferOut);
601 }
602 
setupDispatch(const gl::Context * context,vk::CommandBuffer ** commandBufferOut)603 angle::Result ContextVk::setupDispatch(const gl::Context *context,
604                                        vk::CommandBuffer **commandBufferOut)
605 {
606     ANGLE_TRY(mDispatcher.recordCommands(this, commandBufferOut));
607 
608     if (mProgram->dirtyUniforms())
609     {
610         ANGLE_TRY(mProgram->updateUniforms(this));
611         mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
612     }
613 
614     DirtyBits dirtyBits = mComputeDirtyBits;
615 
616     // Flush any relevant dirty bits.
617     for (size_t dirtyBit : dirtyBits)
618     {
619         ANGLE_TRY((this->*mComputeDirtyBitHandlers[dirtyBit])(context, *commandBufferOut));
620     }
621 
622     mComputeDirtyBits.reset();
623 
624     return angle::Result::Continue;
625 }
626 
handleDirtyGraphicsDefaultAttribs(const gl::Context * context,vk::CommandBuffer * commandBuffer)627 angle::Result ContextVk::handleDirtyGraphicsDefaultAttribs(const gl::Context *context,
628                                                            vk::CommandBuffer *commandBuffer)
629 {
630     ASSERT(mDirtyDefaultAttribsMask.any());
631 
632     for (size_t attribIndex : mDirtyDefaultAttribsMask)
633     {
634         ANGLE_TRY(updateDefaultAttribute(attribIndex));
635     }
636 
637     mDirtyDefaultAttribsMask.reset();
638     return angle::Result::Continue;
639 }
640 
handleDirtyGraphicsPipeline(const gl::Context * context,vk::CommandBuffer * commandBuffer)641 angle::Result ContextVk::handleDirtyGraphicsPipeline(const gl::Context *context,
642                                                      vk::CommandBuffer *commandBuffer)
643 {
644     if (!mCurrentGraphicsPipeline)
645     {
646         const vk::GraphicsPipelineDesc *descPtr;
647 
648         // Draw call shader patching, shader compilation, and pipeline cache query.
649         ANGLE_TRY(
650             mProgram->getGraphicsPipeline(this, mCurrentDrawMode, *mGraphicsPipelineDesc,
651                                           mProgram->getState().getNonBuiltinAttribLocationsMask(),
652                                           &descPtr, &mCurrentGraphicsPipeline));
653         mGraphicsPipelineTransition.reset();
654     }
655     else if (mGraphicsPipelineTransition.any())
656     {
657         if (!mCurrentGraphicsPipeline->findTransition(
658                 mGraphicsPipelineTransition, *mGraphicsPipelineDesc, &mCurrentGraphicsPipeline))
659         {
660             vk::PipelineHelper *oldPipeline = mCurrentGraphicsPipeline;
661 
662             const vk::GraphicsPipelineDesc *descPtr;
663 
664             ANGLE_TRY(mProgram->getGraphicsPipeline(
665                 this, mCurrentDrawMode, *mGraphicsPipelineDesc,
666                 mProgram->getState().getNonBuiltinAttribLocationsMask(), &descPtr,
667                 &mCurrentGraphicsPipeline));
668 
669             oldPipeline->addTransition(mGraphicsPipelineTransition, descPtr,
670                                        mCurrentGraphicsPipeline);
671         }
672 
673         mGraphicsPipelineTransition.reset();
674     }
675     commandBuffer->bindGraphicsPipeline(mCurrentGraphicsPipeline->getPipeline());
676     // Update the queue serial for the pipeline object.
677     ASSERT(mCurrentGraphicsPipeline && mCurrentGraphicsPipeline->valid());
678     mCurrentGraphicsPipeline->updateSerial(getCurrentQueueSerial());
679     return angle::Result::Continue;
680 }
681 
handleDirtyComputePipeline(const gl::Context * context,vk::CommandBuffer * commandBuffer)682 angle::Result ContextVk::handleDirtyComputePipeline(const gl::Context *context,
683                                                     vk::CommandBuffer *commandBuffer)
684 {
685     if (!mCurrentComputePipeline)
686     {
687         ANGLE_TRY(mProgram->getComputePipeline(this, &mCurrentComputePipeline));
688     }
689 
690     commandBuffer->bindComputePipeline(mCurrentComputePipeline->get());
691     mCurrentComputePipeline->updateSerial(getCurrentQueueSerial());
692 
693     return angle::Result::Continue;
694 }
695 
handleDirtyTexturesImpl(const gl::Context * context,vk::CommandBuffer * commandBuffer,vk::CommandGraphResource * recorder)696 ANGLE_INLINE angle::Result ContextVk::handleDirtyTexturesImpl(const gl::Context *context,
697                                                               vk::CommandBuffer *commandBuffer,
698                                                               vk::CommandGraphResource *recorder)
699 {
700 
701     ANGLE_TRY(updateActiveTextures(context, recorder));
702 
703     if (mProgram->hasTextures())
704     {
705         ANGLE_TRY(mProgram->updateTexturesDescriptorSet(this));
706     }
707 
708     return angle::Result::Continue;
709 }
710 
handleDirtyGraphicsTextures(const gl::Context * context,vk::CommandBuffer * commandBuffer)711 angle::Result ContextVk::handleDirtyGraphicsTextures(const gl::Context *context,
712                                                      vk::CommandBuffer *commandBuffer)
713 {
714     return handleDirtyTexturesImpl(context, commandBuffer, mDrawFramebuffer->getFramebuffer());
715 }
716 
handleDirtyComputeTextures(const gl::Context * context,vk::CommandBuffer * commandBuffer)717 angle::Result ContextVk::handleDirtyComputeTextures(const gl::Context *context,
718                                                     vk::CommandBuffer *commandBuffer)
719 {
720     return handleDirtyTexturesImpl(context, commandBuffer, &mDispatcher);
721 }
722 
handleDirtyGraphicsVertexBuffers(const gl::Context * context,vk::CommandBuffer * commandBuffer)723 angle::Result ContextVk::handleDirtyGraphicsVertexBuffers(const gl::Context *context,
724                                                           vk::CommandBuffer *commandBuffer)
725 {
726     uint32_t maxAttrib = mProgram->getState().getMaxActiveAttribLocation();
727     const gl::AttribArray<VkBuffer> &bufferHandles = mVertexArray->getCurrentArrayBufferHandles();
728     const gl::AttribArray<VkDeviceSize> &bufferOffsets =
729         mVertexArray->getCurrentArrayBufferOffsets();
730 
731     commandBuffer->bindVertexBuffers(0, maxAttrib, bufferHandles.data(), bufferOffsets.data());
732 
733     const gl::AttribArray<vk::BufferHelper *> &arrayBufferResources =
734         mVertexArray->getCurrentArrayBuffers();
735     vk::FramebufferHelper *framebuffer = mDrawFramebuffer->getFramebuffer();
736 
737     for (size_t attribIndex : context->getStateCache().getActiveBufferedAttribsMask())
738     {
739         vk::BufferHelper *arrayBuffer = arrayBufferResources[attribIndex];
740         if (arrayBuffer)
741         {
742             arrayBuffer->onRead(framebuffer, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT);
743         }
744     }
745 
746     return angle::Result::Continue;
747 }
748 
handleDirtyGraphicsIndexBuffer(const gl::Context * context,vk::CommandBuffer * commandBuffer)749 angle::Result ContextVk::handleDirtyGraphicsIndexBuffer(const gl::Context *context,
750                                                         vk::CommandBuffer *commandBuffer)
751 {
752     vk::BufferHelper *elementArrayBuffer = mVertexArray->getCurrentElementArrayBuffer();
753     ASSERT(elementArrayBuffer != nullptr);
754 
755     commandBuffer->bindIndexBuffer(elementArrayBuffer->getBuffer(),
756                                    mVertexArray->getCurrentElementArrayBufferOffset(),
757                                    gl_vk::kIndexTypeMap[mCurrentDrawElementsType]);
758 
759     vk::FramebufferHelper *framebuffer = mDrawFramebuffer->getFramebuffer();
760     elementArrayBuffer->onRead(framebuffer, VK_ACCESS_INDEX_READ_BIT);
761 
762     return angle::Result::Continue;
763 }
764 
handleDirtyShaderResourcesImpl(const gl::Context * context,vk::CommandBuffer * commandBuffer,vk::CommandGraphResource * recorder)765 ANGLE_INLINE angle::Result ContextVk::handleDirtyShaderResourcesImpl(
766     const gl::Context *context,
767     vk::CommandBuffer *commandBuffer,
768     vk::CommandGraphResource *recorder)
769 {
770     if (mProgram->hasUniformBuffers() || mProgram->hasStorageBuffers() ||
771         mProgram->hasAtomicCounterBuffers())
772     {
773         ANGLE_TRY(mProgram->updateShaderResourcesDescriptorSet(this, recorder));
774     }
775     return angle::Result::Continue;
776 }
777 
handleDirtyGraphicsShaderResources(const gl::Context * context,vk::CommandBuffer * commandBuffer)778 angle::Result ContextVk::handleDirtyGraphicsShaderResources(const gl::Context *context,
779                                                             vk::CommandBuffer *commandBuffer)
780 {
781     return handleDirtyShaderResourcesImpl(context, commandBuffer,
782                                           mDrawFramebuffer->getFramebuffer());
783 }
784 
handleDirtyComputeShaderResources(const gl::Context * context,vk::CommandBuffer * commandBuffer)785 angle::Result ContextVk::handleDirtyComputeShaderResources(const gl::Context *context,
786                                                            vk::CommandBuffer *commandBuffer)
787 {
788     return handleDirtyShaderResourcesImpl(context, commandBuffer, &mDispatcher);
789 }
790 
handleDirtyGraphicsTransformFeedbackBuffers(const gl::Context * context,vk::CommandBuffer * commandBuffer)791 angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffers(
792     const gl::Context *context,
793     vk::CommandBuffer *commandBuffer)
794 {
795     if (mProgram->hasTransformFeedbackOutput() && mState.isTransformFeedbackActive())
796     {
797         ANGLE_TRY(mProgram->updateTransformFeedbackDescriptorSet(
798             this, mDrawFramebuffer->getFramebuffer()));
799     }
800     return angle::Result::Continue;
801 }
802 
handleDirtyDescriptorSetsImpl(vk::CommandBuffer * commandBuffer,VkPipelineBindPoint bindPoint,const DriverUniformsDescriptorSet & driverUniforms)803 ANGLE_INLINE angle::Result ContextVk::handleDirtyDescriptorSetsImpl(
804     vk::CommandBuffer *commandBuffer,
805     VkPipelineBindPoint bindPoint,
806     const DriverUniformsDescriptorSet &driverUniforms)
807 {
808     ANGLE_TRY(mProgram->updateDescriptorSets(this, commandBuffer));
809 
810     // Bind the driver descriptor set.
811     commandBuffer->bindDescriptorSets(
812         mProgram->getPipelineLayout(), bindPoint, kDriverUniformsDescriptorSetIndex, 1,
813         &driverUniforms.descriptorSet, 1, &driverUniforms.dynamicOffset);
814 
815     return angle::Result::Continue;
816 }
817 
handleDirtyGraphicsDescriptorSets(const gl::Context * context,vk::CommandBuffer * commandBuffer)818 angle::Result ContextVk::handleDirtyGraphicsDescriptorSets(const gl::Context *context,
819                                                            vk::CommandBuffer *commandBuffer)
820 {
821     return handleDirtyDescriptorSetsImpl(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
822                                          mDriverUniforms[PipelineType::Graphics]);
823 }
824 
handleDirtyComputeDescriptorSets(const gl::Context * context,vk::CommandBuffer * commandBuffer)825 angle::Result ContextVk::handleDirtyComputeDescriptorSets(const gl::Context *context,
826                                                           vk::CommandBuffer *commandBuffer)
827 {
828     return handleDirtyDescriptorSetsImpl(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE,
829                                          mDriverUniforms[PipelineType::Compute]);
830 }
831 
releaseToCommandBatch(vk::PrimaryCommandBuffer && commandBuffer,CommandBatch * batch)832 angle::Result ContextVk::releaseToCommandBatch(vk::PrimaryCommandBuffer &&commandBuffer,
833                                                CommandBatch *batch)
834 {
835     batch->primaryCommands = std::move(commandBuffer);
836 
837     if (mCommandPool.valid())
838     {
839         batch->commandPool = std::move(mCommandPool);
840         // Recreate CommandPool
841         VkCommandPoolCreateInfo poolInfo = {};
842         poolInfo.sType                   = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
843         poolInfo.flags                   = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
844         poolInfo.queueFamilyIndex        = getRenderer()->getQueueFamilyIndex();
845 
846         ANGLE_VK_TRY(this, mCommandPool.init(getDevice(), poolInfo));
847     }
848 
849     return angle::Result::Continue;
850 }
851 
recycleCommandBatch(CommandBatch * batch)852 angle::Result ContextVk::recycleCommandBatch(CommandBatch *batch)
853 {
854     batch->commandPool.destroy(getDevice());
855 
856     if (ANGLE_LIKELY(!mRenderer->getFeatures().transientCommandBuffer.enabled))
857     {
858         ASSERT(mPrimaryCommandPool.valid());
859         ANGLE_TRY(mPrimaryCommandPool.collect(this, std::move(batch->primaryCommands)));
860     }
861     else
862     {
863         batch->primaryCommands.destroy(getDevice());
864     }
865 
866     return angle::Result::Continue;
867 }
868 
submitFrame(const VkSubmitInfo & submitInfo,vk::PrimaryCommandBuffer && commandBuffer)869 angle::Result ContextVk::submitFrame(const VkSubmitInfo &submitInfo,
870                                      vk::PrimaryCommandBuffer &&commandBuffer)
871 {
872     ANGLE_TRACE_EVENT0("gpu.angle", "RendererVk::submitFrame");
873     VkFenceCreateInfo fenceInfo = {};
874     fenceInfo.sType             = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
875     fenceInfo.flags             = 0;
876 
877     VkDevice device = getDevice();
878     vk::Scoped<CommandBatch> scopedBatch(device);
879     CommandBatch &batch = scopedBatch.get();
880     ANGLE_TRY(getNextSubmitFence(&batch.fence));
881 
882     ANGLE_TRY(getRenderer()->queueSubmit(this, submitInfo, batch.fence.get()));
883 
884     // TODO: this comment still valid?
885     // Notify the Contexts that they should be starting new command buffers.
886     // We use one command pool per serial/submit associated with this VkQueue. We can also
887     // have multiple Contexts sharing one VkQueue. In ContextVk::setupDraw we don't explicitly
888     // check for a new serial when starting a new command buffer. We just check that the current
889     // recording command buffer is valid. Thus we need to explicitly notify every other Context
890     // using this VkQueue that they their current command buffer is no longer valid.
891     onRenderPassFinished();
892     mComputeDirtyBits |= mNewComputeCommandBufferDirtyBits;
893 
894     // Store the primary CommandBuffer and command pool used for secondary CommandBuffers
895     // in the in-flight list.
896     ANGLE_TRY(releaseToCommandBatch(std::move(commandBuffer), &batch));
897     batch.serial = mCurrentQueueSerial;
898 
899     mInFlightCommands.emplace_back(scopedBatch.release());
900 
901     // Make sure a new fence is created for the next submission.
902     mRenderer->resetSharedFence(&mSubmitFence);
903 
904     // CPU should be throttled to avoid mInFlightCommands from growing too fast.  That is done on
905     // swap() though, and there could be multiple submissions in between (through glFlush() calls),
906     // so the limit is larger than the expected number of images.  The
907     // InterleavedAttributeDataBenchmark perf test for example issues a large number of flushes.
908     ASSERT(mInFlightCommands.size() <= kInFlightCommandsLimit);
909 
910     mLastSubmittedQueueSerial = mCurrentQueueSerial;
911     mCurrentQueueSerial       = getRenderer()->nextSerial();
912 
913     ANGLE_TRY(checkCompletedCommands());
914 
915     if (mGpuEventsEnabled)
916     {
917         ANGLE_TRY(checkCompletedGpuEvents());
918     }
919 
920     return angle::Result::Continue;
921 }
922 
flushCommandGraph(vk::PrimaryCommandBuffer * commandBatch)923 angle::Result ContextVk::flushCommandGraph(vk::PrimaryCommandBuffer *commandBatch)
924 {
925     if (mIsAnyHostVisibleBufferWritten)
926     {
927         mCommandGraph.makeHostVisibleBufferWriteAvailable();
928     }
929     mIsAnyHostVisibleBufferWritten = false;
930 
931     return mCommandGraph.submitCommands(this, mCurrentQueueSerial, &mRenderPassCache, commandBatch);
932 }
933 
synchronizeCpuGpuTime()934 angle::Result ContextVk::synchronizeCpuGpuTime()
935 {
936     ASSERT(mGpuEventsEnabled);
937 
938     angle::PlatformMethods *platform = ANGLEPlatformCurrent();
939     ASSERT(platform);
940 
941     // To synchronize CPU and GPU times, we need to get the CPU timestamp as close as possible to
942     // the GPU timestamp.  The process of getting the GPU timestamp is as follows:
943     //
944     //             CPU                            GPU
945     //
946     //     Record command buffer
947     //     with timestamp query
948     //
949     //     Submit command buffer
950     //
951     //     Post-submission work             Begin execution
952     //
953     //            ????                    Write timestamp Tgpu
954     //
955     //            ????                       End execution
956     //
957     //            ????                    Return query results
958     //
959     //            ????
960     //
961     //       Get query results
962     //
963     // The areas of unknown work (????) on the CPU indicate that the CPU may or may not have
964     // finished post-submission work while the GPU is executing in parallel. With no further work,
965     // querying CPU timestamps before submission and after getting query results give the bounds to
966     // Tgpu, which could be quite large.
967     //
968     // Using VkEvents, the GPU can be made to wait for the CPU and vice versa, in an effort to
969     // reduce this range. This function implements the following procedure:
970     //
971     //             CPU                            GPU
972     //
973     //     Record command buffer
974     //     with timestamp query
975     //
976     //     Submit command buffer
977     //
978     //     Post-submission work             Begin execution
979     //
980     //            ????                    Set Event GPUReady
981     //
982     //    Wait on Event GPUReady         Wait on Event CPUReady
983     //
984     //       Get CPU Time Ts             Wait on Event CPUReady
985     //
986     //      Set Event CPUReady           Wait on Event CPUReady
987     //
988     //      Get CPU Time Tcpu              Get GPU Time Tgpu
989     //
990     //    Wait on Event GPUDone            Set Event GPUDone
991     //
992     //       Get CPU Time Te                 End Execution
993     //
994     //            Idle                    Return query results
995     //
996     //      Get query results
997     //
998     // If Te-Ts > epsilon, a GPU or CPU interruption can be assumed and the operation can be
999     // retried.  Once Te-Ts < epsilon, Tcpu can be taken to presumably match Tgpu.  Finding an
1000     // epsilon that's valid for all devices may be difficult, so the loop can be performed only a
1001     // limited number of times and the Tcpu,Tgpu pair corresponding to smallest Te-Ts used for
1002     // calibration.
1003     //
1004     // Note: Once VK_EXT_calibrated_timestamps is ubiquitous, this should be redone.
1005 
1006     // Make sure nothing is running
1007     ASSERT(mCommandGraph.empty());
1008 
1009     ANGLE_TRACE_EVENT0("gpu.angle", "RendererVk::synchronizeCpuGpuTime");
1010 
1011     // Create a query used to receive the GPU timestamp
1012     vk::QueryHelper timestampQuery;
1013     ANGLE_TRY(mGpuEventQueryPool.allocateQuery(this, &timestampQuery));
1014 
1015     // Create the three events
1016     VkEventCreateInfo eventCreateInfo = {};
1017     eventCreateInfo.sType             = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
1018     eventCreateInfo.flags             = 0;
1019 
1020     VkDevice device = getDevice();
1021     vk::Scoped<vk::Event> cpuReady(device), gpuReady(device), gpuDone(device);
1022     ANGLE_VK_TRY(this, cpuReady.get().init(device, eventCreateInfo));
1023     ANGLE_VK_TRY(this, gpuReady.get().init(device, eventCreateInfo));
1024     ANGLE_VK_TRY(this, gpuDone.get().init(device, eventCreateInfo));
1025 
1026     constexpr uint32_t kRetries = 10;
1027 
1028     // Time suffixes used are S for seconds and Cycles for cycles
1029     double tightestRangeS = 1e6f;
1030     double TcpuS          = 0;
1031     uint64_t TgpuCycles   = 0;
1032     for (uint32_t i = 0; i < kRetries; ++i)
1033     {
1034         // Reset the events
1035         ANGLE_VK_TRY(this, cpuReady.get().reset(device));
1036         ANGLE_VK_TRY(this, gpuReady.get().reset(device));
1037         ANGLE_VK_TRY(this, gpuDone.get().reset(device));
1038 
1039         // Record the command buffer
1040         vk::Scoped<vk::PrimaryCommandBuffer> commandBatch(device);
1041         vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get();
1042 
1043         if (ANGLE_LIKELY(!mRenderer->getFeatures().transientCommandBuffer.enabled))
1044         {
1045             ANGLE_TRY(mPrimaryCommandPool.alloc(this, &commandBuffer));
1046         }
1047         else
1048         {
1049             VkCommandBufferAllocateInfo commandBufferInfo = {};
1050             commandBufferInfo.sType              = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
1051             commandBufferInfo.commandPool        = mCommandPool.getHandle();
1052             commandBufferInfo.level              = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1053             commandBufferInfo.commandBufferCount = 1;
1054 
1055             ANGLE_VK_TRY(this, commandBuffer.init(device, commandBufferInfo));
1056         }
1057 
1058         VkCommandBufferBeginInfo beginInfo = {};
1059         beginInfo.sType                    = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1060         beginInfo.flags                    = 0;
1061         beginInfo.pInheritanceInfo         = nullptr;
1062 
1063         ANGLE_VK_TRY(this, commandBuffer.begin(beginInfo));
1064 
1065         commandBuffer.setEvent(gpuReady.get().getHandle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
1066         commandBuffer.waitEvents(1, cpuReady.get().ptr(), VK_PIPELINE_STAGE_HOST_BIT,
1067                                  VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, nullptr, 0, nullptr, 0,
1068                                  nullptr);
1069 
1070         commandBuffer.resetQueryPool(timestampQuery.getQueryPool()->getHandle(),
1071                                      timestampQuery.getQuery(), 1);
1072         commandBuffer.writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1073                                      timestampQuery.getQueryPool()->getHandle(),
1074                                      timestampQuery.getQuery());
1075 
1076         commandBuffer.setEvent(gpuDone.get().getHandle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
1077 
1078         ANGLE_VK_TRY(this, commandBuffer.end());
1079 
1080         // Submit the command buffer
1081         VkSubmitInfo submitInfo = {};
1082         InitializeSubmitInfo(&submitInfo, commandBatch.get(), {}, &mWaitSemaphoreStageMasks,
1083                              nullptr);
1084 
1085         ANGLE_TRY(submitFrame(submitInfo, commandBatch.release()));
1086 
1087         // Wait for GPU to be ready.  This is a short busy wait.
1088         VkResult result = VK_EVENT_RESET;
1089         do
1090         {
1091             result = gpuReady.get().getStatus(device);
1092             if (result != VK_EVENT_SET && result != VK_EVENT_RESET)
1093             {
1094                 ANGLE_VK_TRY(this, result);
1095             }
1096         } while (result == VK_EVENT_RESET);
1097 
1098         double TsS = platform->monotonicallyIncreasingTime(platform);
1099 
1100         // Tell the GPU to go ahead with the timestamp query.
1101         ANGLE_VK_TRY(this, cpuReady.get().set(device));
1102         double cpuTimestampS = platform->monotonicallyIncreasingTime(platform);
1103 
1104         // Wait for GPU to be done.  Another short busy wait.
1105         do
1106         {
1107             result = gpuDone.get().getStatus(device);
1108             if (result != VK_EVENT_SET && result != VK_EVENT_RESET)
1109             {
1110                 ANGLE_VK_TRY(this, result);
1111             }
1112         } while (result == VK_EVENT_RESET);
1113 
1114         double TeS = platform->monotonicallyIncreasingTime(platform);
1115 
1116         // Get the query results
1117         ANGLE_TRY(finishToSerial(getLastSubmittedQueueSerial()));
1118 
1119         constexpr VkQueryResultFlags queryFlags = VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_64_BIT;
1120 
1121         uint64_t gpuTimestampCycles = 0;
1122         ANGLE_VK_TRY(this, timestampQuery.getQueryPool()->getResults(
1123                                device, timestampQuery.getQuery(), 1, sizeof(gpuTimestampCycles),
1124                                &gpuTimestampCycles, sizeof(gpuTimestampCycles), queryFlags));
1125 
1126         // Use the first timestamp queried as origin.
1127         if (mGpuEventTimestampOrigin == 0)
1128         {
1129             mGpuEventTimestampOrigin = gpuTimestampCycles;
1130         }
1131 
1132         // Take these CPU and GPU timestamps if there is better confidence.
1133         double confidenceRangeS = TeS - TsS;
1134         if (confidenceRangeS < tightestRangeS)
1135         {
1136             tightestRangeS = confidenceRangeS;
1137             TcpuS          = cpuTimestampS;
1138             TgpuCycles     = gpuTimestampCycles;
1139         }
1140     }
1141 
1142     mGpuEventQueryPool.freeQuery(this, &timestampQuery);
1143 
1144     // timestampPeriod gives nanoseconds/cycle.
1145     double TgpuS =
1146         (TgpuCycles - mGpuEventTimestampOrigin) *
1147         static_cast<double>(getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod) /
1148         1'000'000'000.0;
1149 
1150     flushGpuEvents(TgpuS, TcpuS);
1151 
1152     mGpuClockSync.gpuTimestampS = TgpuS;
1153     mGpuClockSync.cpuTimestampS = TcpuS;
1154 
1155     return angle::Result::Continue;
1156 }
1157 
traceGpuEventImpl(vk::PrimaryCommandBuffer * commandBuffer,char phase,const char * name)1158 angle::Result ContextVk::traceGpuEventImpl(vk::PrimaryCommandBuffer *commandBuffer,
1159                                            char phase,
1160                                            const char *name)
1161 {
1162     ASSERT(mGpuEventsEnabled);
1163 
1164     GpuEventQuery event;
1165 
1166     event.name   = name;
1167     event.phase  = phase;
1168     event.serial = mCurrentQueueSerial;
1169 
1170     ANGLE_TRY(mGpuEventQueryPool.allocateQuery(this, &event.queryPoolIndex, &event.queryIndex));
1171 
1172     commandBuffer->resetQueryPool(
1173         mGpuEventQueryPool.getQueryPool(event.queryPoolIndex)->getHandle(), event.queryIndex, 1);
1174     commandBuffer->writeTimestamp(
1175         VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1176         mGpuEventQueryPool.getQueryPool(event.queryPoolIndex)->getHandle(), event.queryIndex);
1177 
1178     mInFlightGpuEventQueries.push_back(std::move(event));
1179 
1180     return angle::Result::Continue;
1181 }
1182 
checkCompletedGpuEvents()1183 angle::Result ContextVk::checkCompletedGpuEvents()
1184 {
1185     ASSERT(mGpuEventsEnabled);
1186 
1187     angle::PlatformMethods *platform = ANGLEPlatformCurrent();
1188     ASSERT(platform);
1189 
1190     int finishedCount = 0;
1191 
1192     for (GpuEventQuery &eventQuery : mInFlightGpuEventQueries)
1193     {
1194         // Only check the timestamp query if the submission has finished.
1195         if (eventQuery.serial > mLastCompletedQueueSerial)
1196         {
1197             break;
1198         }
1199 
1200         // See if the results are available.
1201         uint64_t gpuTimestampCycles = 0;
1202         VkResult result             = mGpuEventQueryPool.getQueryPool(eventQuery.queryPoolIndex)
1203                               ->getResults(getDevice(), eventQuery.queryIndex, 1,
1204                                            sizeof(gpuTimestampCycles), &gpuTimestampCycles,
1205                                            sizeof(gpuTimestampCycles), VK_QUERY_RESULT_64_BIT);
1206         if (result == VK_NOT_READY)
1207         {
1208             break;
1209         }
1210         ANGLE_VK_TRY(this, result);
1211 
1212         mGpuEventQueryPool.freeQuery(this, eventQuery.queryPoolIndex, eventQuery.queryIndex);
1213 
1214         GpuEvent event;
1215         event.gpuTimestampCycles = gpuTimestampCycles;
1216         event.name               = eventQuery.name;
1217         event.phase              = eventQuery.phase;
1218 
1219         mGpuEvents.emplace_back(event);
1220 
1221         ++finishedCount;
1222     }
1223 
1224     mInFlightGpuEventQueries.erase(mInFlightGpuEventQueries.begin(),
1225                                    mInFlightGpuEventQueries.begin() + finishedCount);
1226 
1227     return angle::Result::Continue;
1228 }
1229 
flushGpuEvents(double nextSyncGpuTimestampS,double nextSyncCpuTimestampS)1230 void ContextVk::flushGpuEvents(double nextSyncGpuTimestampS, double nextSyncCpuTimestampS)
1231 {
1232     if (mGpuEvents.size() == 0)
1233     {
1234         return;
1235     }
1236 
1237     angle::PlatformMethods *platform = ANGLEPlatformCurrent();
1238     ASSERT(platform);
1239 
1240     // Find the slope of the clock drift for adjustment
1241     double lastGpuSyncTimeS  = mGpuClockSync.gpuTimestampS;
1242     double lastGpuSyncDiffS  = mGpuClockSync.cpuTimestampS - mGpuClockSync.gpuTimestampS;
1243     double gpuSyncDriftSlope = 0;
1244 
1245     double nextGpuSyncTimeS = nextSyncGpuTimestampS;
1246     double nextGpuSyncDiffS = nextSyncCpuTimestampS - nextSyncGpuTimestampS;
1247 
1248     // No gpu trace events should have been generated before the clock sync, so if there is no
1249     // "previous" clock sync, there should be no gpu events (i.e. the function early-outs above).
1250     ASSERT(mGpuClockSync.gpuTimestampS != std::numeric_limits<double>::max() &&
1251            mGpuClockSync.cpuTimestampS != std::numeric_limits<double>::max());
1252 
1253     gpuSyncDriftSlope =
1254         (nextGpuSyncDiffS - lastGpuSyncDiffS) / (nextGpuSyncTimeS - lastGpuSyncTimeS);
1255 
1256     for (const GpuEvent &event : mGpuEvents)
1257     {
1258         double gpuTimestampS =
1259             (event.gpuTimestampCycles - mGpuEventTimestampOrigin) *
1260             static_cast<double>(
1261                 getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod) *
1262             1e-9;
1263 
1264         // Account for clock drift.
1265         gpuTimestampS += lastGpuSyncDiffS + gpuSyncDriftSlope * (gpuTimestampS - lastGpuSyncTimeS);
1266 
1267         // Generate the trace now that the GPU timestamp is available and clock drifts are accounted
1268         // for.
1269         static long long eventId = 1;
1270         static const unsigned char *categoryEnabled =
1271             TRACE_EVENT_API_GET_CATEGORY_ENABLED(platform, "gpu.angle.gpu");
1272         platform->addTraceEvent(platform, event.phase, categoryEnabled, event.name, eventId++,
1273                                 gpuTimestampS, 0, nullptr, nullptr, nullptr, TRACE_EVENT_FLAG_NONE);
1274     }
1275 
1276     mGpuEvents.clear();
1277 }
1278 
handleDeviceLost()1279 void ContextVk::handleDeviceLost()
1280 {
1281     mCommandGraph.clear();
1282     // TODO: generate a new serial neccessary here?
1283     VkDevice device = getDevice();
1284 
1285     for (CommandBatch &batch : mInFlightCommands)
1286     {
1287         // On device loss we need to wait for fence to be signaled before destroying it
1288         VkResult status = batch.fence.get().wait(device, kMaxFenceWaitTimeNs);
1289         // If the wait times out, it is probably not possible to recover from lost device
1290         ASSERT(status == VK_SUCCESS || status == VK_ERROR_DEVICE_LOST);
1291 
1292         // On device lost, here simply destroy the CommandBuffer, it will fully cleared later
1293         // by CommandPool::destroy
1294         batch.primaryCommands.destroy(device);
1295 
1296         batch.commandPool.destroy(device);
1297         batch.fence.reset(device);
1298     }
1299     mInFlightCommands.clear();
1300 
1301     for (vk::GarbageObject &garbage : mGarbage)
1302     {
1303         garbage.destroy(device);
1304     }
1305     mGarbage.clear();
1306 
1307     mLastCompletedQueueSerial = mLastSubmittedQueueSerial;
1308 
1309     mRenderer->notifyDeviceLost();
1310 }
1311 
drawArrays(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count)1312 angle::Result ContextVk::drawArrays(const gl::Context *context,
1313                                     gl::PrimitiveMode mode,
1314                                     GLint first,
1315                                     GLsizei count)
1316 {
1317     vk::CommandBuffer *commandBuffer = nullptr;
1318     uint32_t clampedVertexCount      = gl::GetClampedVertexCount<uint32_t>(count);
1319 
1320     if (mode == gl::PrimitiveMode::LineLoop)
1321     {
1322         uint32_t numIndices;
1323         ANGLE_TRY(setupLineLoopDraw(context, mode, first, count, gl::DrawElementsType::InvalidEnum,
1324                                     nullptr, &commandBuffer, &numIndices));
1325         vk::LineLoopHelper::Draw(numIndices, commandBuffer);
1326     }
1327     else
1328     {
1329         ANGLE_TRY(setupDraw(context, mode, first, count, 1, gl::DrawElementsType::InvalidEnum,
1330                             nullptr, mNonIndexedDirtyBitsMask, &commandBuffer));
1331         commandBuffer->draw(clampedVertexCount, first);
1332     }
1333 
1334     return angle::Result::Continue;
1335 }
1336 
drawArraysInstanced(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instances)1337 angle::Result ContextVk::drawArraysInstanced(const gl::Context *context,
1338                                              gl::PrimitiveMode mode,
1339                                              GLint first,
1340                                              GLsizei count,
1341                                              GLsizei instances)
1342 {
1343     if (mode == gl::PrimitiveMode::LineLoop)
1344     {
1345         // TODO - http://anglebug.com/2672
1346         ANGLE_VK_UNREACHABLE(this);
1347         return angle::Result::Stop;
1348     }
1349 
1350     vk::CommandBuffer *commandBuffer = nullptr;
1351     ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum,
1352                         nullptr, mNonIndexedDirtyBitsMask, &commandBuffer));
1353     commandBuffer->drawInstanced(gl::GetClampedVertexCount<uint32_t>(count), instances, first);
1354     return angle::Result::Continue;
1355 }
1356 
drawArraysInstancedBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instances,GLuint baseInstance)1357 angle::Result ContextVk::drawArraysInstancedBaseInstance(const gl::Context *context,
1358                                                          gl::PrimitiveMode mode,
1359                                                          GLint first,
1360                                                          GLsizei count,
1361                                                          GLsizei instances,
1362                                                          GLuint baseInstance)
1363 {
1364     UNIMPLEMENTED();
1365     return angle::Result::Continue;
1366 }
1367 
drawElements(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices)1368 angle::Result ContextVk::drawElements(const gl::Context *context,
1369                                       gl::PrimitiveMode mode,
1370                                       GLsizei count,
1371                                       gl::DrawElementsType type,
1372                                       const void *indices)
1373 {
1374     vk::CommandBuffer *commandBuffer = nullptr;
1375     if (mode == gl::PrimitiveMode::LineLoop)
1376     {
1377         uint32_t indexCount;
1378         ANGLE_TRY(
1379             setupLineLoopDraw(context, mode, 0, count, type, indices, &commandBuffer, &indexCount));
1380         vk::LineLoopHelper::Draw(indexCount, commandBuffer);
1381     }
1382     else
1383     {
1384         ANGLE_TRY(setupIndexedDraw(context, mode, count, 1, type, indices, &commandBuffer));
1385         commandBuffer->drawIndexed(count);
1386     }
1387 
1388     return angle::Result::Continue;
1389 }
1390 
drawElementsInstanced(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances)1391 angle::Result ContextVk::drawElementsInstanced(const gl::Context *context,
1392                                                gl::PrimitiveMode mode,
1393                                                GLsizei count,
1394                                                gl::DrawElementsType type,
1395                                                const void *indices,
1396                                                GLsizei instances)
1397 {
1398     if (mode == gl::PrimitiveMode::LineLoop)
1399     {
1400         // TODO - http://anglebug.com/2672
1401         ANGLE_VK_UNREACHABLE(this);
1402         return angle::Result::Stop;
1403     }
1404 
1405     vk::CommandBuffer *commandBuffer = nullptr;
1406     ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices, &commandBuffer));
1407     commandBuffer->drawIndexedInstanced(count, instances);
1408     return angle::Result::Continue;
1409 }
1410 
drawElementsInstancedBaseVertexBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances,GLint baseVertex,GLuint baseInstance)1411 angle::Result ContextVk::drawElementsInstancedBaseVertexBaseInstance(const gl::Context *context,
1412                                                                      gl::PrimitiveMode mode,
1413                                                                      GLsizei count,
1414                                                                      gl::DrawElementsType type,
1415                                                                      const void *indices,
1416                                                                      GLsizei instances,
1417                                                                      GLint baseVertex,
1418                                                                      GLuint baseInstance)
1419 {
1420     UNIMPLEMENTED();
1421     return angle::Result::Continue;
1422 }
1423 
drawRangeElements(const gl::Context * context,gl::PrimitiveMode mode,GLuint start,GLuint end,GLsizei count,gl::DrawElementsType type,const void * indices)1424 angle::Result ContextVk::drawRangeElements(const gl::Context *context,
1425                                            gl::PrimitiveMode mode,
1426                                            GLuint start,
1427                                            GLuint end,
1428                                            GLsizei count,
1429                                            gl::DrawElementsType type,
1430                                            const void *indices)
1431 {
1432     return drawElements(context, mode, count, type, indices);
1433 }
1434 
getDevice() const1435 VkDevice ContextVk::getDevice() const
1436 {
1437     return mRenderer->getDevice();
1438 }
1439 
drawArraysIndirect(const gl::Context * context,gl::PrimitiveMode mode,const void * indirect)1440 angle::Result ContextVk::drawArraysIndirect(const gl::Context *context,
1441                                             gl::PrimitiveMode mode,
1442                                             const void *indirect)
1443 {
1444     ANGLE_VK_UNREACHABLE(this);
1445     return angle::Result::Stop;
1446 }
1447 
drawElementsIndirect(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType type,const void * indirect)1448 angle::Result ContextVk::drawElementsIndirect(const gl::Context *context,
1449                                               gl::PrimitiveMode mode,
1450                                               gl::DrawElementsType type,
1451                                               const void *indirect)
1452 {
1453     ANGLE_VK_UNREACHABLE(this);
1454     return angle::Result::Stop;
1455 }
1456 
getResetStatus()1457 gl::GraphicsResetStatus ContextVk::getResetStatus()
1458 {
1459     if (mRenderer->isDeviceLost())
1460     {
1461         // TODO(geofflang): It may be possible to track which context caused the device lost and
1462         // return either GL_GUILTY_CONTEXT_RESET or GL_INNOCENT_CONTEXT_RESET.
1463         // http://anglebug.com/2787
1464         return gl::GraphicsResetStatus::UnknownContextReset;
1465     }
1466 
1467     return gl::GraphicsResetStatus::NoError;
1468 }
1469 
getVendorString() const1470 std::string ContextVk::getVendorString() const
1471 {
1472     UNIMPLEMENTED();
1473     return std::string();
1474 }
1475 
getRendererDescription() const1476 std::string ContextVk::getRendererDescription() const
1477 {
1478     return mRenderer->getRendererDescription();
1479 }
1480 
insertEventMarker(GLsizei length,const char * marker)1481 void ContextVk::insertEventMarker(GLsizei length, const char *marker)
1482 {
1483     std::string markerStr(marker, length <= 0 ? strlen(marker) : length);
1484     mCommandGraph.insertDebugMarker(GL_DEBUG_SOURCE_APPLICATION, std::move(marker));
1485 }
1486 
pushGroupMarker(GLsizei length,const char * marker)1487 void ContextVk::pushGroupMarker(GLsizei length, const char *marker)
1488 {
1489     std::string markerStr(marker, length <= 0 ? strlen(marker) : length);
1490     mCommandGraph.pushDebugMarker(GL_DEBUG_SOURCE_APPLICATION, std::move(marker));
1491 }
1492 
popGroupMarker()1493 void ContextVk::popGroupMarker()
1494 {
1495     mCommandGraph.popDebugMarker();
1496 }
1497 
pushDebugGroup(GLenum source,GLuint id,const std::string & message)1498 void ContextVk::pushDebugGroup(GLenum source, GLuint id, const std::string &message)
1499 {
1500     mCommandGraph.insertDebugMarker(source, std::string(message));
1501 }
1502 
popDebugGroup()1503 void ContextVk::popDebugGroup()
1504 {
1505     mCommandGraph.popDebugMarker();
1506 }
1507 
isViewportFlipEnabledForDrawFBO() const1508 bool ContextVk::isViewportFlipEnabledForDrawFBO() const
1509 {
1510     return mFlipViewportForDrawFramebuffer && mFlipYForCurrentSurface;
1511 }
1512 
isViewportFlipEnabledForReadFBO() const1513 bool ContextVk::isViewportFlipEnabledForReadFBO() const
1514 {
1515     return mFlipViewportForReadFramebuffer;
1516 }
1517 
updateColorMask(const gl::BlendState & blendState)1518 void ContextVk::updateColorMask(const gl::BlendState &blendState)
1519 {
1520     mClearColorMask =
1521         gl_vk::GetColorComponentFlags(blendState.colorMaskRed, blendState.colorMaskGreen,
1522                                       blendState.colorMaskBlue, blendState.colorMaskAlpha);
1523 
1524     FramebufferVk *framebufferVk = vk::GetImpl(mState.getDrawFramebuffer());
1525     mGraphicsPipelineDesc->updateColorWriteMask(&mGraphicsPipelineTransition, mClearColorMask,
1526                                                 framebufferVk->getEmulatedAlphaAttachmentMask());
1527 }
1528 
updateSampleMask(const gl::State & glState)1529 void ContextVk::updateSampleMask(const gl::State &glState)
1530 {
1531     // If sample coverage is enabled, emulate it by generating and applying a mask on top of the
1532     // sample mask.
1533     uint32_t coverageSampleCount = GetCoverageSampleCount(glState, mDrawFramebuffer);
1534 
1535     static_assert(sizeof(uint32_t) == sizeof(GLbitfield), "Vulkan assumes 32-bit sample masks");
1536     for (uint32_t maskNumber = 0; maskNumber < glState.getMaxSampleMaskWords(); ++maskNumber)
1537     {
1538         uint32_t mask = glState.isSampleMaskEnabled() ? glState.getSampleMaskWord(maskNumber)
1539                                                       : std::numeric_limits<uint32_t>::max();
1540 
1541         ApplySampleCoverage(glState, coverageSampleCount, maskNumber, &mask);
1542 
1543         mGraphicsPipelineDesc->updateSampleMask(&mGraphicsPipelineTransition, maskNumber, mask);
1544     }
1545 }
1546 
updateViewport(FramebufferVk * framebufferVk,const gl::Rectangle & viewport,float nearPlane,float farPlane,bool invertViewport)1547 void ContextVk::updateViewport(FramebufferVk *framebufferVk,
1548                                const gl::Rectangle &viewport,
1549                                float nearPlane,
1550                                float farPlane,
1551                                bool invertViewport)
1552 {
1553     VkViewport vkViewport;
1554     const gl::Caps &caps                   = getCaps();
1555     const VkPhysicalDeviceLimits &limitsVk = mRenderer->getPhysicalDeviceProperties().limits;
1556     const int viewportBoundsRangeLow       = static_cast<int>(limitsVk.viewportBoundsRange[0]);
1557     const int viewportBoundsRangeHigh      = static_cast<int>(limitsVk.viewportBoundsRange[1]);
1558 
1559     // Clamp the viewport values to what Vulkan specifies
1560 
1561     // width must be greater than 0.0 and less than or equal to
1562     // VkPhysicalDeviceLimits::maxViewportDimensions[0]
1563     int correctedWidth = std::min<int>(viewport.width, caps.maxViewportWidth);
1564     correctedWidth     = std::max<int>(correctedWidth, 0);
1565     // height must be greater than 0.0 and less than or equal to
1566     // VkPhysicalDeviceLimits::maxViewportDimensions[1]
1567     int correctedHeight = std::min<int>(viewport.height, caps.maxViewportHeight);
1568     correctedHeight     = std::max<int>(correctedHeight, 0);
1569     // x and y must each be between viewportBoundsRange[0] and viewportBoundsRange[1], inclusive
1570     int correctedX = std::min<int>(viewport.x, viewportBoundsRangeHigh);
1571     correctedX     = std::max<int>(correctedX, viewportBoundsRangeLow);
1572     int correctedY = std::min<int>(viewport.y, viewportBoundsRangeHigh);
1573     correctedY     = std::max<int>(correctedY, viewportBoundsRangeLow);
1574     // x + width must be less than or equal to viewportBoundsRange[1]
1575     if ((correctedX + correctedWidth) > viewportBoundsRangeHigh)
1576     {
1577         correctedWidth = viewportBoundsRangeHigh - correctedX;
1578     }
1579     // y + height must be less than or equal to viewportBoundsRange[1]
1580     if ((correctedY + correctedHeight) > viewportBoundsRangeHigh)
1581     {
1582         correctedHeight = viewportBoundsRangeHigh - correctedY;
1583     }
1584 
1585     gl::Rectangle correctedRect =
1586         gl::Rectangle(correctedX, correctedY, correctedWidth, correctedHeight);
1587 
1588     gl_vk::GetViewport(correctedRect, nearPlane, farPlane, invertViewport,
1589                        framebufferVk->getState().getDimensions().height, &vkViewport);
1590     mGraphicsPipelineDesc->updateViewport(&mGraphicsPipelineTransition, vkViewport);
1591     invalidateGraphicsDriverUniforms();
1592 }
1593 
updateDepthRange(float nearPlane,float farPlane)1594 void ContextVk::updateDepthRange(float nearPlane, float farPlane)
1595 {
1596     invalidateGraphicsDriverUniforms();
1597     mGraphicsPipelineDesc->updateDepthRange(&mGraphicsPipelineTransition, nearPlane, farPlane);
1598 }
1599 
updateScissor(const gl::State & glState)1600 void ContextVk::updateScissor(const gl::State &glState)
1601 {
1602     FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer());
1603     gl::Rectangle renderArea     = framebufferVk->getCompleteRenderArea();
1604 
1605     // Clip the render area to the viewport.
1606     gl::Rectangle viewportClippedRenderArea;
1607     gl::ClipRectangle(renderArea, glState.getViewport(), &viewportClippedRenderArea);
1608 
1609     gl::Rectangle scissoredArea = ClipRectToScissor(getState(), viewportClippedRenderArea, false);
1610     if (isViewportFlipEnabledForDrawFBO())
1611     {
1612         scissoredArea.y = renderArea.height - scissoredArea.y - scissoredArea.height;
1613     }
1614 
1615     if (getRenderer()->getFeatures().forceNonZeroScissor.enabled && scissoredArea.width == 0 &&
1616         scissoredArea.height == 0)
1617     {
1618         // There is no overlap between the app-set viewport and clippedRect.  This code works
1619         // around an Intel driver bug that causes the driver to treat a (0,0,0,0) scissor as if
1620         // scissoring is disabled.  In this case, set the scissor to be just outside of the
1621         // renderArea.  Remove this work-around when driver version 25.20.100.6519 has been
1622         // deployed.  http://anglebug.com/3407
1623         scissoredArea.x      = renderArea.x;
1624         scissoredArea.y      = renderArea.y;
1625         scissoredArea.width  = 1;
1626         scissoredArea.height = 1;
1627     }
1628     mGraphicsPipelineDesc->updateScissor(&mGraphicsPipelineTransition,
1629                                          gl_vk::GetRect(scissoredArea));
1630 
1631     framebufferVk->onScissorChange(this);
1632 }
1633 
syncState(const gl::Context * context,const gl::State::DirtyBits & dirtyBits,const gl::State::DirtyBits & bitMask)1634 angle::Result ContextVk::syncState(const gl::Context *context,
1635                                    const gl::State::DirtyBits &dirtyBits,
1636                                    const gl::State::DirtyBits &bitMask)
1637 {
1638     const gl::State &glState = context->getState();
1639 
1640     if ((dirtyBits & mPipelineDirtyBitsMask).any() &&
1641         (glState.getProgram() == nullptr || !glState.getProgram()->isCompute()))
1642     {
1643         invalidateVertexAndIndexBuffers();
1644     }
1645 
1646     for (size_t dirtyBit : dirtyBits)
1647     {
1648         switch (dirtyBit)
1649         {
1650             case gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED:
1651             case gl::State::DIRTY_BIT_SCISSOR:
1652                 updateScissor(glState);
1653                 break;
1654             case gl::State::DIRTY_BIT_VIEWPORT:
1655             {
1656                 FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer());
1657                 updateViewport(framebufferVk, glState.getViewport(), glState.getNearPlane(),
1658                                glState.getFarPlane(), isViewportFlipEnabledForDrawFBO());
1659                 // Update the scissor, which will be constrained to the viewport
1660                 updateScissor(glState);
1661                 break;
1662             }
1663             case gl::State::DIRTY_BIT_DEPTH_RANGE:
1664                 updateDepthRange(glState.getNearPlane(), glState.getFarPlane());
1665                 break;
1666             case gl::State::DIRTY_BIT_BLEND_ENABLED:
1667                 mGraphicsPipelineDesc->updateBlendEnabled(&mGraphicsPipelineTransition,
1668                                                           glState.isBlendEnabled());
1669                 break;
1670             case gl::State::DIRTY_BIT_BLEND_COLOR:
1671                 mGraphicsPipelineDesc->updateBlendColor(&mGraphicsPipelineTransition,
1672                                                         glState.getBlendColor());
1673                 break;
1674             case gl::State::DIRTY_BIT_BLEND_FUNCS:
1675                 mGraphicsPipelineDesc->updateBlendFuncs(&mGraphicsPipelineTransition,
1676                                                         glState.getBlendState());
1677                 break;
1678             case gl::State::DIRTY_BIT_BLEND_EQUATIONS:
1679                 mGraphicsPipelineDesc->updateBlendEquations(&mGraphicsPipelineTransition,
1680                                                             glState.getBlendState());
1681                 break;
1682             case gl::State::DIRTY_BIT_COLOR_MASK:
1683                 updateColorMask(glState.getBlendState());
1684                 break;
1685             case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
1686                 mGraphicsPipelineDesc->updateAlphaToCoverageEnable(
1687                     &mGraphicsPipelineTransition, glState.isSampleAlphaToCoverageEnabled());
1688                 break;
1689             case gl::State::DIRTY_BIT_SAMPLE_COVERAGE_ENABLED:
1690                 updateSampleMask(glState);
1691                 break;
1692             case gl::State::DIRTY_BIT_SAMPLE_COVERAGE:
1693                 updateSampleMask(glState);
1694                 break;
1695             case gl::State::DIRTY_BIT_SAMPLE_MASK_ENABLED:
1696                 updateSampleMask(glState);
1697                 break;
1698             case gl::State::DIRTY_BIT_SAMPLE_MASK:
1699                 updateSampleMask(glState);
1700                 break;
1701             case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED:
1702                 mGraphicsPipelineDesc->updateDepthTestEnabled(&mGraphicsPipelineTransition,
1703                                                               glState.getDepthStencilState(),
1704                                                               glState.getDrawFramebuffer());
1705                 break;
1706             case gl::State::DIRTY_BIT_DEPTH_FUNC:
1707                 mGraphicsPipelineDesc->updateDepthFunc(&mGraphicsPipelineTransition,
1708                                                        glState.getDepthStencilState());
1709                 break;
1710             case gl::State::DIRTY_BIT_DEPTH_MASK:
1711                 mGraphicsPipelineDesc->updateDepthWriteEnabled(&mGraphicsPipelineTransition,
1712                                                                glState.getDepthStencilState(),
1713                                                                glState.getDrawFramebuffer());
1714                 break;
1715             case gl::State::DIRTY_BIT_STENCIL_TEST_ENABLED:
1716                 mGraphicsPipelineDesc->updateStencilTestEnabled(&mGraphicsPipelineTransition,
1717                                                                 glState.getDepthStencilState(),
1718                                                                 glState.getDrawFramebuffer());
1719                 break;
1720             case gl::State::DIRTY_BIT_STENCIL_FUNCS_FRONT:
1721                 mGraphicsPipelineDesc->updateStencilFrontFuncs(&mGraphicsPipelineTransition,
1722                                                                glState.getStencilRef(),
1723                                                                glState.getDepthStencilState());
1724                 break;
1725             case gl::State::DIRTY_BIT_STENCIL_FUNCS_BACK:
1726                 mGraphicsPipelineDesc->updateStencilBackFuncs(&mGraphicsPipelineTransition,
1727                                                               glState.getStencilBackRef(),
1728                                                               glState.getDepthStencilState());
1729                 break;
1730             case gl::State::DIRTY_BIT_STENCIL_OPS_FRONT:
1731                 mGraphicsPipelineDesc->updateStencilFrontOps(&mGraphicsPipelineTransition,
1732                                                              glState.getDepthStencilState());
1733                 break;
1734             case gl::State::DIRTY_BIT_STENCIL_OPS_BACK:
1735                 mGraphicsPipelineDesc->updateStencilBackOps(&mGraphicsPipelineTransition,
1736                                                             glState.getDepthStencilState());
1737                 break;
1738             case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT:
1739                 mGraphicsPipelineDesc->updateStencilFrontWriteMask(&mGraphicsPipelineTransition,
1740                                                                    glState.getDepthStencilState(),
1741                                                                    glState.getDrawFramebuffer());
1742                 break;
1743             case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK:
1744                 mGraphicsPipelineDesc->updateStencilBackWriteMask(&mGraphicsPipelineTransition,
1745                                                                   glState.getDepthStencilState(),
1746                                                                   glState.getDrawFramebuffer());
1747                 break;
1748             case gl::State::DIRTY_BIT_CULL_FACE_ENABLED:
1749             case gl::State::DIRTY_BIT_CULL_FACE:
1750                 mGraphicsPipelineDesc->updateCullMode(&mGraphicsPipelineTransition,
1751                                                       glState.getRasterizerState());
1752                 break;
1753             case gl::State::DIRTY_BIT_FRONT_FACE:
1754                 mGraphicsPipelineDesc->updateFrontFace(&mGraphicsPipelineTransition,
1755                                                        glState.getRasterizerState(),
1756                                                        isViewportFlipEnabledForDrawFBO());
1757                 break;
1758             case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED:
1759                 mGraphicsPipelineDesc->updatePolygonOffsetFillEnabled(
1760                     &mGraphicsPipelineTransition, glState.isPolygonOffsetFillEnabled());
1761                 break;
1762             case gl::State::DIRTY_BIT_POLYGON_OFFSET:
1763                 mGraphicsPipelineDesc->updatePolygonOffset(&mGraphicsPipelineTransition,
1764                                                            glState.getRasterizerState());
1765                 break;
1766             case gl::State::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED:
1767                 mGraphicsPipelineDesc->updateRasterizerDiscardEnabled(
1768                     &mGraphicsPipelineTransition, glState.isRasterizerDiscardEnabled());
1769                 break;
1770             case gl::State::DIRTY_BIT_LINE_WIDTH:
1771                 mGraphicsPipelineDesc->updateLineWidth(&mGraphicsPipelineTransition,
1772                                                        glState.getLineWidth());
1773                 break;
1774             case gl::State::DIRTY_BIT_PRIMITIVE_RESTART_ENABLED:
1775                 mGraphicsPipelineDesc->updatePrimitiveRestartEnabled(
1776                     &mGraphicsPipelineTransition, glState.isPrimitiveRestartEnabled());
1777                 break;
1778             case gl::State::DIRTY_BIT_CLEAR_COLOR:
1779                 mClearColorValue.color.float32[0] = glState.getColorClearValue().red;
1780                 mClearColorValue.color.float32[1] = glState.getColorClearValue().green;
1781                 mClearColorValue.color.float32[2] = glState.getColorClearValue().blue;
1782                 mClearColorValue.color.float32[3] = glState.getColorClearValue().alpha;
1783                 break;
1784             case gl::State::DIRTY_BIT_CLEAR_DEPTH:
1785                 mClearDepthStencilValue.depthStencil.depth = glState.getDepthClearValue();
1786                 break;
1787             case gl::State::DIRTY_BIT_CLEAR_STENCIL:
1788                 mClearDepthStencilValue.depthStencil.stencil =
1789                     static_cast<uint32_t>(glState.getStencilClearValue());
1790                 break;
1791             case gl::State::DIRTY_BIT_UNPACK_STATE:
1792                 // This is a no-op, its only important to use the right unpack state when we do
1793                 // setImage or setSubImage in TextureVk, which is plumbed through the frontend call
1794                 break;
1795             case gl::State::DIRTY_BIT_UNPACK_BUFFER_BINDING:
1796                 break;
1797             case gl::State::DIRTY_BIT_PACK_STATE:
1798                 // This is a no-op, its only important to use the right pack state when we do
1799                 // call readPixels later on.
1800                 break;
1801             case gl::State::DIRTY_BIT_PACK_BUFFER_BINDING:
1802                 break;
1803             case gl::State::DIRTY_BIT_DITHER_ENABLED:
1804                 break;
1805             case gl::State::DIRTY_BIT_GENERATE_MIPMAP_HINT:
1806                 break;
1807             case gl::State::DIRTY_BIT_SHADER_DERIVATIVE_HINT:
1808                 break;
1809             case gl::State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING:
1810                 updateFlipViewportReadFramebuffer(context->getState());
1811                 break;
1812             case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING:
1813             {
1814                 // FramebufferVk::syncState signals that we should start a new command buffer. But
1815                 // changing the binding can skip FramebufferVk::syncState if the Framebuffer has no
1816                 // dirty bits. Thus we need to explicitly clear the current command buffer to
1817                 // ensure we start a new one. Note that we need a new command buffer because a
1818                 // command graph node can only support one RenderPass configuration at a time.
1819                 onRenderPassFinished();
1820 
1821                 mDrawFramebuffer = vk::GetImpl(glState.getDrawFramebuffer());
1822                 updateFlipViewportDrawFramebuffer(glState);
1823                 updateViewport(mDrawFramebuffer, glState.getViewport(), glState.getNearPlane(),
1824                                glState.getFarPlane(), isViewportFlipEnabledForDrawFBO());
1825                 updateColorMask(glState.getBlendState());
1826                 updateSampleMask(glState);
1827                 mGraphicsPipelineDesc->updateRasterizationSamples(&mGraphicsPipelineTransition,
1828                                                                   mDrawFramebuffer->getSamples());
1829                 mGraphicsPipelineDesc->updateFrontFace(&mGraphicsPipelineTransition,
1830                                                        glState.getRasterizerState(),
1831                                                        isViewportFlipEnabledForDrawFBO());
1832                 updateScissor(glState);
1833                 mGraphicsPipelineDesc->updateDepthTestEnabled(&mGraphicsPipelineTransition,
1834                                                               glState.getDepthStencilState(),
1835                                                               glState.getDrawFramebuffer());
1836                 mGraphicsPipelineDesc->updateDepthWriteEnabled(&mGraphicsPipelineTransition,
1837                                                                glState.getDepthStencilState(),
1838                                                                glState.getDrawFramebuffer());
1839                 mGraphicsPipelineDesc->updateStencilTestEnabled(&mGraphicsPipelineTransition,
1840                                                                 glState.getDepthStencilState(),
1841                                                                 glState.getDrawFramebuffer());
1842                 mGraphicsPipelineDesc->updateStencilFrontWriteMask(&mGraphicsPipelineTransition,
1843                                                                    glState.getDepthStencilState(),
1844                                                                    glState.getDrawFramebuffer());
1845                 mGraphicsPipelineDesc->updateStencilBackWriteMask(&mGraphicsPipelineTransition,
1846                                                                   glState.getDepthStencilState(),
1847                                                                   glState.getDrawFramebuffer());
1848                 mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition,
1849                                                             mDrawFramebuffer->getRenderPassDesc());
1850                 invalidateCurrentTransformFeedbackBuffers();
1851                 break;
1852             }
1853             case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING:
1854                 break;
1855             case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING:
1856             {
1857                 mVertexArray = vk::GetImpl(glState.getVertexArray());
1858                 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask());
1859                 break;
1860             }
1861             case gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING:
1862                 break;
1863             case gl::State::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING:
1864                 break;
1865             case gl::State::DIRTY_BIT_PROGRAM_BINDING:
1866                 mProgram = vk::GetImpl(glState.getProgram());
1867                 break;
1868             case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
1869             {
1870                 invalidateCurrentTextures();
1871                 invalidateCurrentShaderResources();
1872                 if (glState.getProgram()->isCompute())
1873                 {
1874                     invalidateCurrentComputePipeline();
1875                 }
1876                 else
1877                 {
1878                     // No additional work is needed here. We will update the pipeline desc later.
1879                     invalidateDefaultAttributes(
1880                         context->getStateCache().getActiveDefaultAttribsMask());
1881                     bool useVertexBuffer = (mProgram->getState().getMaxActiveAttribLocation());
1882                     mNonIndexedDirtyBitsMask.set(DIRTY_BIT_VERTEX_BUFFERS, useVertexBuffer);
1883                     mIndexedDirtyBitsMask.set(DIRTY_BIT_VERTEX_BUFFERS, useVertexBuffer);
1884                     mCurrentGraphicsPipeline = nullptr;
1885                     mGraphicsPipelineTransition.reset();
1886                 }
1887                 break;
1888             }
1889             case gl::State::DIRTY_BIT_TEXTURE_BINDINGS:
1890                 invalidateCurrentTextures();
1891                 break;
1892             case gl::State::DIRTY_BIT_SAMPLER_BINDINGS:
1893                 invalidateCurrentTextures();
1894                 break;
1895             case gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING:
1896                 // Nothing to do.
1897                 break;
1898             case gl::State::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING:
1899                 invalidateCurrentShaderResources();
1900                 break;
1901             case gl::State::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS:
1902                 invalidateCurrentShaderResources();
1903                 break;
1904             case gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING:
1905                 invalidateCurrentShaderResources();
1906                 invalidateDriverUniforms();
1907                 break;
1908             case gl::State::DIRTY_BIT_IMAGE_BINDINGS:
1909                 break;
1910             case gl::State::DIRTY_BIT_MULTISAMPLING:
1911                 // TODO(syoussefi): this should configure the pipeline to render as if
1912                 // single-sampled, and write the results to all samples of a pixel regardless of
1913                 // coverage. See EXT_multisample_compatibility.  http://anglebug.com/3204
1914                 break;
1915             case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_ONE:
1916                 // TODO(syoussefi): this is part of EXT_multisample_compatibility.  The alphaToOne
1917                 // Vulkan feature should be enabled to support this extension.
1918                 // http://anglebug.com/3204
1919                 mGraphicsPipelineDesc->updateAlphaToOneEnable(&mGraphicsPipelineTransition,
1920                                                               glState.isSampleAlphaToOneEnabled());
1921                 break;
1922             case gl::State::DIRTY_BIT_COVERAGE_MODULATION:
1923                 break;
1924             case gl::State::DIRTY_BIT_PATH_RENDERING:
1925                 break;
1926             case gl::State::DIRTY_BIT_FRAMEBUFFER_SRGB:
1927                 break;
1928             case gl::State::DIRTY_BIT_CURRENT_VALUES:
1929             {
1930                 invalidateDefaultAttributes(glState.getAndResetDirtyCurrentValues());
1931                 break;
1932             }
1933             case gl::State::DIRTY_BIT_PROVOKING_VERTEX:
1934                 break;
1935             default:
1936                 UNREACHABLE();
1937                 break;
1938         }
1939     }
1940 
1941     return angle::Result::Continue;
1942 }
1943 
getGPUDisjoint()1944 GLint ContextVk::getGPUDisjoint()
1945 {
1946     // No extension seems to be available to query this information.
1947     return 0;
1948 }
1949 
getTimestamp()1950 GLint64 ContextVk::getTimestamp()
1951 {
1952     uint64_t timestamp = 0;
1953 
1954     (void)getTimestamp(&timestamp);
1955 
1956     return static_cast<GLint64>(timestamp);
1957 }
1958 
onMakeCurrent(const gl::Context * context)1959 angle::Result ContextVk::onMakeCurrent(const gl::Context *context)
1960 {
1961     ASSERT(mCommandGraph.empty());
1962     mCurrentQueueSerial = getRenderer()->nextSerial();
1963 
1964     // Flip viewports if FeaturesVk::flipViewportY is enabled and the user did not request that the
1965     // surface is flipped.
1966     egl::Surface *drawSurface = context->getCurrentDrawSurface();
1967     mFlipYForCurrentSurface =
1968         drawSurface != nullptr && mRenderer->getFeatures().flipViewportY.enabled &&
1969         !IsMaskFlagSet(drawSurface->getOrientation(), EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE);
1970 
1971     if (drawSurface && drawSurface->getType() == EGL_WINDOW_BIT)
1972     {
1973         mCurrentWindowSurface = GetImplAs<WindowSurfaceVk>(drawSurface);
1974     }
1975     else
1976     {
1977         mCurrentWindowSurface = nullptr;
1978     }
1979 
1980     const gl::State &glState = context->getState();
1981     updateFlipViewportDrawFramebuffer(glState);
1982     updateFlipViewportReadFramebuffer(glState);
1983     invalidateDriverUniforms();
1984 
1985     return angle::Result::Continue;
1986 }
1987 
onUnMakeCurrent(const gl::Context * context)1988 angle::Result ContextVk::onUnMakeCurrent(const gl::Context *context)
1989 {
1990     ANGLE_TRY(flushImpl(nullptr));
1991     mCurrentWindowSurface = nullptr;
1992     return angle::Result::Continue;
1993 }
1994 
updateFlipViewportDrawFramebuffer(const gl::State & glState)1995 void ContextVk::updateFlipViewportDrawFramebuffer(const gl::State &glState)
1996 {
1997     gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
1998     mFlipViewportForDrawFramebuffer =
1999         drawFramebuffer->isDefault() && mRenderer->getFeatures().flipViewportY.enabled;
2000 }
2001 
updateFlipViewportReadFramebuffer(const gl::State & glState)2002 void ContextVk::updateFlipViewportReadFramebuffer(const gl::State &glState)
2003 {
2004     gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
2005     mFlipViewportForReadFramebuffer =
2006         readFramebuffer->isDefault() && mRenderer->getFeatures().flipViewportY.enabled;
2007 }
2008 
getNativeCaps() const2009 gl::Caps ContextVk::getNativeCaps() const
2010 {
2011     return mRenderer->getNativeCaps();
2012 }
2013 
getNativeTextureCaps() const2014 const gl::TextureCapsMap &ContextVk::getNativeTextureCaps() const
2015 {
2016     return mRenderer->getNativeTextureCaps();
2017 }
2018 
getNativeExtensions() const2019 const gl::Extensions &ContextVk::getNativeExtensions() const
2020 {
2021     return mRenderer->getNativeExtensions();
2022 }
2023 
getNativeLimitations() const2024 const gl::Limitations &ContextVk::getNativeLimitations() const
2025 {
2026     return mRenderer->getNativeLimitations();
2027 }
2028 
createCompiler()2029 CompilerImpl *ContextVk::createCompiler()
2030 {
2031     return new CompilerVk();
2032 }
2033 
createShader(const gl::ShaderState & state)2034 ShaderImpl *ContextVk::createShader(const gl::ShaderState &state)
2035 {
2036     return new ShaderVk(state);
2037 }
2038 
createProgram(const gl::ProgramState & state)2039 ProgramImpl *ContextVk::createProgram(const gl::ProgramState &state)
2040 {
2041     return new ProgramVk(state);
2042 }
2043 
createFramebuffer(const gl::FramebufferState & state)2044 FramebufferImpl *ContextVk::createFramebuffer(const gl::FramebufferState &state)
2045 {
2046     return FramebufferVk::CreateUserFBO(mRenderer, state);
2047 }
2048 
createTexture(const gl::TextureState & state)2049 TextureImpl *ContextVk::createTexture(const gl::TextureState &state)
2050 {
2051     return new TextureVk(state, mRenderer);
2052 }
2053 
createRenderbuffer(const gl::RenderbufferState & state)2054 RenderbufferImpl *ContextVk::createRenderbuffer(const gl::RenderbufferState &state)
2055 {
2056     return new RenderbufferVk(state);
2057 }
2058 
createBuffer(const gl::BufferState & state)2059 BufferImpl *ContextVk::createBuffer(const gl::BufferState &state)
2060 {
2061     return new BufferVk(state);
2062 }
2063 
createVertexArray(const gl::VertexArrayState & state)2064 VertexArrayImpl *ContextVk::createVertexArray(const gl::VertexArrayState &state)
2065 {
2066     return new VertexArrayVk(this, state);
2067 }
2068 
createQuery(gl::QueryType type)2069 QueryImpl *ContextVk::createQuery(gl::QueryType type)
2070 {
2071     return new QueryVk(type);
2072 }
2073 
createFenceNV()2074 FenceNVImpl *ContextVk::createFenceNV()
2075 {
2076     return new FenceNVVk();
2077 }
2078 
createSync()2079 SyncImpl *ContextVk::createSync()
2080 {
2081     return new SyncVk();
2082 }
2083 
createTransformFeedback(const gl::TransformFeedbackState & state)2084 TransformFeedbackImpl *ContextVk::createTransformFeedback(const gl::TransformFeedbackState &state)
2085 {
2086     return new TransformFeedbackVk(state);
2087 }
2088 
createSampler(const gl::SamplerState & state)2089 SamplerImpl *ContextVk::createSampler(const gl::SamplerState &state)
2090 {
2091     return new SamplerVk(state);
2092 }
2093 
createProgramPipeline(const gl::ProgramPipelineState & state)2094 ProgramPipelineImpl *ContextVk::createProgramPipeline(const gl::ProgramPipelineState &state)
2095 {
2096     return new ProgramPipelineVk(state);
2097 }
2098 
createPaths(GLsizei)2099 std::vector<PathImpl *> ContextVk::createPaths(GLsizei)
2100 {
2101     return std::vector<PathImpl *>();
2102 }
2103 
createMemoryObject()2104 MemoryObjectImpl *ContextVk::createMemoryObject()
2105 {
2106     return new MemoryObjectVk();
2107 }
2108 
createSemaphore()2109 SemaphoreImpl *ContextVk::createSemaphore()
2110 {
2111     return new SemaphoreVk();
2112 }
2113 
invalidateCurrentTextures()2114 void ContextVk::invalidateCurrentTextures()
2115 {
2116     ASSERT(mProgram);
2117     if (mProgram->hasTextures())
2118     {
2119         mGraphicsDirtyBits.set(DIRTY_BIT_TEXTURES);
2120         mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
2121         mComputeDirtyBits.set(DIRTY_BIT_TEXTURES);
2122         mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
2123     }
2124 }
2125 
invalidateCurrentShaderResources()2126 void ContextVk::invalidateCurrentShaderResources()
2127 {
2128     ASSERT(mProgram);
2129     if (mProgram->hasUniformBuffers() || mProgram->hasStorageBuffers() ||
2130         mProgram->hasAtomicCounterBuffers())
2131     {
2132         mGraphicsDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES);
2133         mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
2134         mComputeDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES);
2135         mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
2136     }
2137 }
2138 
invalidateGraphicsDriverUniforms()2139 void ContextVk::invalidateGraphicsDriverUniforms()
2140 {
2141     mGraphicsDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS);
2142     mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
2143 }
2144 
invalidateDriverUniforms()2145 void ContextVk::invalidateDriverUniforms()
2146 {
2147     mGraphicsDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS);
2148     mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
2149     mComputeDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS);
2150     mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
2151 }
2152 
onDrawFramebufferChange(FramebufferVk * framebufferVk)2153 void ContextVk::onDrawFramebufferChange(FramebufferVk *framebufferVk)
2154 {
2155     const vk::RenderPassDesc &renderPassDesc = framebufferVk->getRenderPassDesc();
2156 
2157     // Ensure that the RenderPass description is updated.
2158     invalidateCurrentGraphicsPipeline();
2159     mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition, renderPassDesc);
2160 }
2161 
invalidateCurrentTransformFeedbackBuffers()2162 void ContextVk::invalidateCurrentTransformFeedbackBuffers()
2163 {
2164     mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
2165     mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
2166 }
2167 
onTransformFeedbackPauseResume()2168 void ContextVk::onTransformFeedbackPauseResume()
2169 {
2170     invalidateGraphicsDriverUniforms();
2171 }
2172 
dispatchCompute(const gl::Context * context,GLuint numGroupsX,GLuint numGroupsY,GLuint numGroupsZ)2173 angle::Result ContextVk::dispatchCompute(const gl::Context *context,
2174                                          GLuint numGroupsX,
2175                                          GLuint numGroupsY,
2176                                          GLuint numGroupsZ)
2177 {
2178     vk::CommandBuffer *commandBuffer;
2179     ANGLE_TRY(setupDispatch(context, &commandBuffer));
2180 
2181     commandBuffer->dispatch(numGroupsX, numGroupsY, numGroupsZ);
2182 
2183     return angle::Result::Continue;
2184 }
2185 
dispatchComputeIndirect(const gl::Context * context,GLintptr indirect)2186 angle::Result ContextVk::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect)
2187 {
2188     vk::CommandBuffer *commandBuffer;
2189     ANGLE_TRY(setupDispatch(context, &commandBuffer));
2190 
2191     gl::Buffer *glBuffer     = getState().getTargetBuffer(gl::BufferBinding::DispatchIndirect);
2192     vk::BufferHelper &buffer = vk::GetImpl(glBuffer)->getBuffer();
2193     buffer.onRead(&mDispatcher, VK_ACCESS_INDIRECT_COMMAND_READ_BIT);
2194 
2195     commandBuffer->dispatchIndirect(buffer.getBuffer(), indirect);
2196 
2197     return angle::Result::Continue;
2198 }
2199 
memoryBarrier(const gl::Context * context,GLbitfield barriers)2200 angle::Result ContextVk::memoryBarrier(const gl::Context *context, GLbitfield barriers)
2201 {
2202     // Note: most of the barriers specified here don't require us to issue a memory barrier, as the
2203     // relevant resources already insert the appropriate barriers.  They do however require the
2204     // resource writing nodes to finish so future buffer barriers are placed correctly, as well as
2205     // resource dependencies not creating a graph loop.  This is done by inserting a command graph
2206     // barrier that does nothing!
2207 
2208     VkAccessFlags srcAccess = 0;
2209     VkAccessFlags dstAccess = 0;
2210 
2211     if ((barriers & GL_COMMAND_BARRIER_BIT) != 0)
2212     {
2213         srcAccess |= VK_ACCESS_SHADER_WRITE_BIT;
2214         dstAccess |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
2215     }
2216 
2217     mCommandGraph.memoryBarrier(srcAccess, dstAccess, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
2218     return angle::Result::Continue;
2219 }
2220 
memoryBarrierByRegion(const gl::Context * context,GLbitfield barriers)2221 angle::Result ContextVk::memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers)
2222 {
2223     // There aren't any barrier bits here that aren't otherwise automatically handled.  We only
2224     // need to make sure writer resources (framebuffers and the dispatcher) start a new node.
2225     //
2226     // Note: memoryBarrierByRegion is expected to affect only the fragment pipeline.  Specifying
2227     // that here is currently unnecessary, but is a reminder of this fact in case we do need to
2228     // especially handle some future barrier bit.
2229 
2230     mCommandGraph.memoryBarrier(0, 0, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
2231     return angle::Result::Continue;
2232 }
2233 
getQueryPool(gl::QueryType queryType)2234 vk::DynamicQueryPool *ContextVk::getQueryPool(gl::QueryType queryType)
2235 {
2236     ASSERT(queryType == gl::QueryType::AnySamples ||
2237            queryType == gl::QueryType::AnySamplesConservative ||
2238            queryType == gl::QueryType::Timestamp || queryType == gl::QueryType::TimeElapsed);
2239     ASSERT(mQueryPools[queryType].isValid());
2240     return &mQueryPools[queryType];
2241 }
2242 
getClearColorValue() const2243 const VkClearValue &ContextVk::getClearColorValue() const
2244 {
2245     return mClearColorValue;
2246 }
2247 
getClearDepthStencilValue() const2248 const VkClearValue &ContextVk::getClearDepthStencilValue() const
2249 {
2250     return mClearDepthStencilValue;
2251 }
2252 
getClearColorMask() const2253 VkColorComponentFlags ContextVk::getClearColorMask() const
2254 {
2255     return mClearColorMask;
2256 }
2257 
writeAtomicCounterBufferDriverUniformOffsets(uint32_t * offsetsOut,size_t offsetsSize)2258 void ContextVk::writeAtomicCounterBufferDriverUniformOffsets(uint32_t *offsetsOut,
2259                                                              size_t offsetsSize)
2260 {
2261     const VkDeviceSize offsetAlignment =
2262         mRenderer->getPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
2263     size_t atomicCounterBufferCount = mState.getAtomicCounterBufferCount();
2264 
2265     ASSERT(atomicCounterBufferCount <= offsetsSize * 4);
2266 
2267     for (uint32_t bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
2268     {
2269         uint32_t offsetDiff = 0;
2270 
2271         const gl::OffsetBindingPointer<gl::Buffer> *atomicCounterBuffer =
2272             &mState.getIndexedAtomicCounterBuffer(bufferIndex);
2273         if (atomicCounterBuffer->get())
2274         {
2275             VkDeviceSize offset        = atomicCounterBuffer->getOffset();
2276             VkDeviceSize alignedOffset = (offset / offsetAlignment) * offsetAlignment;
2277 
2278             // GL requires the atomic counter buffer offset to be aligned with uint.
2279             ASSERT((offset - alignedOffset) % sizeof(uint32_t) == 0);
2280             offsetDiff = static_cast<uint32_t>((offset - alignedOffset) / sizeof(uint32_t));
2281 
2282             // We expect offsetDiff to fit in an 8-bit value.  The maximum difference is
2283             // minStorageBufferOffsetAlignment / 4, where minStorageBufferOffsetAlignment currently
2284             // has a maximum value of 256 on any device.
2285             ASSERT(offsetDiff < (1 << 8));
2286         }
2287 
2288         // The output array is already cleared prior to this call.
2289         ASSERT(bufferIndex % 4 != 0 || offsetsOut[bufferIndex / 4] == 0);
2290 
2291         offsetsOut[bufferIndex / 4] |= static_cast<uint8_t>(offsetDiff) << ((bufferIndex % 4) * 8);
2292     }
2293 }
2294 
handleDirtyGraphicsDriverUniforms(const gl::Context * context,vk::CommandBuffer * commandBuffer)2295 angle::Result ContextVk::handleDirtyGraphicsDriverUniforms(const gl::Context *context,
2296                                                            vk::CommandBuffer *commandBuffer)
2297 {
2298     // Allocate a new region in the dynamic buffer.
2299     uint8_t *ptr;
2300     VkBuffer buffer;
2301     bool newBuffer;
2302     ANGLE_TRY(allocateDriverUniforms(sizeof(GraphicsDriverUniforms),
2303                                      &mDriverUniforms[PipelineType::Graphics], &buffer, &ptr,
2304                                      &newBuffer));
2305 
2306     const gl::Rectangle &glViewport = mState.getViewport();
2307     float halfRenderAreaHeight =
2308         static_cast<float>(mDrawFramebuffer->getState().getDimensions().height) * 0.5f;
2309     float scaleY = isViewportFlipEnabledForDrawFBO() ? -1.0f : 1.0f;
2310 
2311     uint32_t xfbActiveUnpaused = mState.isTransformFeedbackActiveUnpaused();
2312 
2313     float depthRangeNear = mState.getNearPlane();
2314     float depthRangeFar  = mState.getFarPlane();
2315     float depthRangeDiff = depthRangeFar - depthRangeNear;
2316 
2317     // Copy and flush to the device.
2318     GraphicsDriverUniforms *driverUniforms = reinterpret_cast<GraphicsDriverUniforms *>(ptr);
2319     *driverUniforms                        = {
2320         {static_cast<float>(glViewport.x), static_cast<float>(glViewport.y),
2321          static_cast<float>(glViewport.width), static_cast<float>(glViewport.height)},
2322         halfRenderAreaHeight,
2323         scaleY,
2324         -scaleY,
2325         xfbActiveUnpaused,
2326         {},
2327         {},
2328         {depthRangeNear, depthRangeFar, depthRangeDiff, 0.0f}};
2329 
2330     if (xfbActiveUnpaused)
2331     {
2332         TransformFeedbackVk *transformFeedbackVk =
2333             vk::GetImpl(mState.getCurrentTransformFeedback());
2334         transformFeedbackVk->getBufferOffsets(this, mState.getProgram()->getState(), mXfbBaseVertex,
2335                                               driverUniforms->xfbBufferOffsets.data(),
2336                                               driverUniforms->xfbBufferOffsets.size());
2337     }
2338 
2339     writeAtomicCounterBufferDriverUniformOffsets(driverUniforms->acbBufferOffsets.data(),
2340                                                  driverUniforms->acbBufferOffsets.size());
2341 
2342     return updateDriverUniformsDescriptorSet(buffer, newBuffer, sizeof(GraphicsDriverUniforms),
2343                                              &mDriverUniforms[PipelineType::Graphics]);
2344 }
2345 
handleDirtyComputeDriverUniforms(const gl::Context * context,vk::CommandBuffer * commandBuffer)2346 angle::Result ContextVk::handleDirtyComputeDriverUniforms(const gl::Context *context,
2347                                                           vk::CommandBuffer *commandBuffer)
2348 {
2349     // Allocate a new region in the dynamic buffer.
2350     uint8_t *ptr;
2351     VkBuffer buffer;
2352     bool newBuffer;
2353     ANGLE_TRY(allocateDriverUniforms(sizeof(ComputeDriverUniforms),
2354                                      &mDriverUniforms[PipelineType::Compute], &buffer, &ptr,
2355                                      &newBuffer));
2356 
2357     // Copy and flush to the device.
2358     ComputeDriverUniforms *driverUniforms = reinterpret_cast<ComputeDriverUniforms *>(ptr);
2359     *driverUniforms                       = {};
2360 
2361     writeAtomicCounterBufferDriverUniformOffsets(driverUniforms->acbBufferOffsets.data(),
2362                                                  driverUniforms->acbBufferOffsets.size());
2363 
2364     return updateDriverUniformsDescriptorSet(buffer, newBuffer, sizeof(ComputeDriverUniforms),
2365                                              &mDriverUniforms[PipelineType::Compute]);
2366 }
2367 
allocateDriverUniforms(size_t driverUniformsSize,DriverUniformsDescriptorSet * driverUniforms,VkBuffer * bufferOut,uint8_t ** ptrOut,bool * newBufferOut)2368 angle::Result ContextVk::allocateDriverUniforms(size_t driverUniformsSize,
2369                                                 DriverUniformsDescriptorSet *driverUniforms,
2370                                                 VkBuffer *bufferOut,
2371                                                 uint8_t **ptrOut,
2372                                                 bool *newBufferOut)
2373 {
2374     // Release any previously retained buffers.
2375     driverUniforms->dynamicBuffer.releaseInFlightBuffers(this);
2376 
2377     // Allocate a new region in the dynamic buffer.
2378     VkDeviceSize offset;
2379     ANGLE_TRY(driverUniforms->dynamicBuffer.allocate(this, driverUniformsSize, ptrOut, bufferOut,
2380                                                      &offset, newBufferOut));
2381 
2382     driverUniforms->dynamicOffset = static_cast<uint32_t>(offset);
2383 
2384     return angle::Result::Continue;
2385 }
2386 
updateDriverUniformsDescriptorSet(VkBuffer buffer,bool newBuffer,size_t driverUniformsSize,DriverUniformsDescriptorSet * driverUniforms)2387 angle::Result ContextVk::updateDriverUniformsDescriptorSet(
2388     VkBuffer buffer,
2389     bool newBuffer,
2390     size_t driverUniformsSize,
2391     DriverUniformsDescriptorSet *driverUniforms)
2392 {
2393     ANGLE_TRY(driverUniforms->dynamicBuffer.flush(this));
2394 
2395     if (!newBuffer)
2396     {
2397         return angle::Result::Continue;
2398     }
2399 
2400     // Allocate a new descriptor set.
2401     ANGLE_TRY(mDriverUniformsDescriptorPool.allocateSets(
2402         this, driverUniforms->descriptorSetLayout.get().ptr(), 1,
2403         &driverUniforms->descriptorPoolBinding, &driverUniforms->descriptorSet));
2404 
2405     // Update the driver uniform descriptor set.
2406     VkDescriptorBufferInfo bufferInfo = {};
2407     bufferInfo.buffer                 = buffer;
2408     bufferInfo.offset                 = 0;
2409     bufferInfo.range                  = driverUniformsSize;
2410 
2411     VkWriteDescriptorSet writeInfo = {};
2412     writeInfo.sType                = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
2413     writeInfo.dstSet               = driverUniforms->descriptorSet;
2414     writeInfo.dstBinding           = 0;
2415     writeInfo.dstArrayElement      = 0;
2416     writeInfo.descriptorCount      = 1;
2417     writeInfo.descriptorType       = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
2418     writeInfo.pImageInfo           = nullptr;
2419     writeInfo.pTexelBufferView     = nullptr;
2420     writeInfo.pBufferInfo          = &bufferInfo;
2421 
2422     vkUpdateDescriptorSets(getDevice(), 1, &writeInfo, 0, nullptr);
2423 
2424     return angle::Result::Continue;
2425 }
2426 
handleError(VkResult errorCode,const char * file,const char * function,unsigned int line)2427 void ContextVk::handleError(VkResult errorCode,
2428                             const char *file,
2429                             const char *function,
2430                             unsigned int line)
2431 {
2432     ASSERT(errorCode != VK_SUCCESS);
2433 
2434     GLenum glErrorCode = DefaultGLErrorCode(errorCode);
2435 
2436     std::stringstream errorStream;
2437     errorStream << "Internal Vulkan error: " << VulkanResultString(errorCode) << ".";
2438 
2439     if (errorCode == VK_ERROR_DEVICE_LOST)
2440     {
2441         WARN() << errorStream.str();
2442         handleDeviceLost();
2443     }
2444 
2445     mErrors->handleError(glErrorCode, errorStream.str().c_str(), file, function, line);
2446 }
2447 
updateActiveTextures(const gl::Context * context,vk::CommandGraphResource * recorder)2448 angle::Result ContextVk::updateActiveTextures(const gl::Context *context,
2449                                               vk::CommandGraphResource *recorder)
2450 {
2451     const gl::State &glState   = mState;
2452     const gl::Program *program = glState.getProgram();
2453 
2454     uint32_t prevMaxIndex = mActiveTexturesDesc.getMaxIndex();
2455     memset(mActiveTextures.data(), 0, sizeof(mActiveTextures[0]) * prevMaxIndex);
2456     mActiveTexturesDesc.reset();
2457 
2458     const gl::ActiveTexturePointerArray &textures  = glState.getActiveTexturesCache();
2459     const gl::ActiveTextureMask &activeTextures    = program->getActiveSamplersMask();
2460     const gl::ActiveTextureTypeArray &textureTypes = program->getActiveSamplerTypes();
2461 
2462     for (size_t textureUnit : activeTextures)
2463     {
2464         gl::Texture *texture        = textures[textureUnit];
2465         gl::Sampler *sampler        = mState.getSampler(static_cast<uint32_t>(textureUnit));
2466         gl::TextureType textureType = textureTypes[textureUnit];
2467 
2468         // Null textures represent incomplete textures.
2469         if (texture == nullptr)
2470         {
2471             ANGLE_TRY(getIncompleteTexture(context, textureType, &texture));
2472         }
2473 
2474         TextureVk *textureVk = vk::GetImpl(texture);
2475         SamplerVk *samplerVk = (sampler != nullptr) ? vk::GetImpl(sampler) : nullptr;
2476 
2477         vk::ImageHelper &image = textureVk->getImage();
2478 
2479         // The image should be flushed and ready to use at this point. There may still be lingering
2480         // staged updates in its staging buffer for unused texture mip levels or layers. Therefore
2481         // we can't verify it has no staged updates right here.
2482 
2483         vk::ImageLayout textureLayout = vk::ImageLayout::AllGraphicsShadersReadOnly;
2484         if (program->isCompute())
2485         {
2486             textureLayout = vk::ImageLayout::ComputeShaderReadOnly;
2487         }
2488 
2489         // Ensure the image is in read-only layout
2490         if (image.isLayoutChangeNecessary(textureLayout))
2491         {
2492             vk::CommandBuffer *srcLayoutChange;
2493             ANGLE_TRY(image.recordCommands(this, &srcLayoutChange));
2494 
2495             VkImageAspectFlags aspectFlags = image.getAspectFlags();
2496             ASSERT(aspectFlags != 0);
2497             image.changeLayout(aspectFlags, textureLayout, srcLayoutChange);
2498         }
2499 
2500         image.addReadDependency(recorder);
2501 
2502         mActiveTextures[textureUnit].texture = textureVk;
2503         mActiveTextures[textureUnit].sampler = samplerVk;
2504         // Cache serials from sampler and texture, but re-use texture if no sampler bound
2505         ASSERT(textureVk != nullptr);
2506         mActiveTexturesDesc.update(textureUnit, textureVk->getSerial(),
2507                                    (samplerVk != nullptr) ? samplerVk->getSerial() : kZeroSerial);
2508     }
2509 
2510     return angle::Result::Continue;
2511 }
2512 
getActiveTextures() const2513 const gl::ActiveTextureArray<vk::TextureUnit> &ContextVk::getActiveTextures() const
2514 {
2515     return mActiveTextures;
2516 }
2517 
insertWaitSemaphore(const vk::Semaphore * waitSemaphore)2518 void ContextVk::insertWaitSemaphore(const vk::Semaphore *waitSemaphore)
2519 {
2520     ASSERT(waitSemaphore);
2521     mWaitSemaphores.push_back(waitSemaphore->getHandle());
2522 }
2523 
flushImpl(const vk::Semaphore * signalSemaphore)2524 angle::Result ContextVk::flushImpl(const vk::Semaphore *signalSemaphore)
2525 {
2526     if (mCommandGraph.empty() && !signalSemaphore && mWaitSemaphores.empty())
2527     {
2528         return angle::Result::Continue;
2529     }
2530 
2531     ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::flush");
2532 
2533     vk::Scoped<vk::PrimaryCommandBuffer> commandBatch(getDevice());
2534     if (ANGLE_LIKELY(!mRenderer->getFeatures().transientCommandBuffer.enabled))
2535     {
2536         ANGLE_TRY(mPrimaryCommandPool.alloc(this, &commandBatch.get()));
2537     }
2538     else
2539     {
2540         VkCommandBufferAllocateInfo commandBufferInfo = {};
2541         commandBufferInfo.sType              = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
2542         commandBufferInfo.commandPool        = mCommandPool.getHandle();
2543         commandBufferInfo.level              = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
2544         commandBufferInfo.commandBufferCount = 1;
2545 
2546         ANGLE_VK_TRY(this, commandBatch.get().init(getDevice(), commandBufferInfo));
2547     }
2548 
2549     if (!mCommandGraph.empty())
2550     {
2551         ANGLE_TRY(flushCommandGraph(&commandBatch.get()));
2552     }
2553 
2554     waitForSwapchainImageIfNecessary();
2555 
2556     VkSubmitInfo submitInfo = {};
2557     InitializeSubmitInfo(&submitInfo, commandBatch.get(), mWaitSemaphores,
2558                          &mWaitSemaphoreStageMasks, signalSemaphore);
2559 
2560     ANGLE_TRY(submitFrame(submitInfo, commandBatch.release()));
2561 
2562     mWaitSemaphores.clear();
2563 
2564     return angle::Result::Continue;
2565 }
2566 
finishImpl()2567 angle::Result ContextVk::finishImpl()
2568 {
2569     ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::finish");
2570 
2571     ANGLE_TRY(flushImpl(nullptr));
2572 
2573     ANGLE_TRY(finishToSerial(mLastSubmittedQueueSerial));
2574     ASSERT(mInFlightCommands.empty());
2575 
2576     for (vk::GarbageObject &garbage : mGarbage)
2577     {
2578         garbage.destroy(getDevice());
2579     }
2580     mGarbage.clear();
2581 
2582     if (mGpuEventsEnabled)
2583     {
2584         // This loop should in practice execute once since the queue is already idle.
2585         while (mInFlightGpuEventQueries.size() > 0)
2586         {
2587             ANGLE_TRY(checkCompletedGpuEvents());
2588         }
2589         // Recalculate the CPU/GPU time difference to account for clock drifting.  Avoid unnecessary
2590         // synchronization if there is no event to be adjusted (happens when finish() gets called
2591         // multiple times towards the end of the application).
2592         if (mGpuEvents.size() > 0)
2593         {
2594             ANGLE_TRY(synchronizeCpuGpuTime());
2595         }
2596     }
2597 
2598     return angle::Result::Continue;
2599 }
2600 
addWaitSemaphore(VkSemaphore semaphore)2601 void ContextVk::addWaitSemaphore(VkSemaphore semaphore)
2602 {
2603     mWaitSemaphores.push_back(semaphore);
2604 }
2605 
getCommandPool() const2606 const vk::CommandPool &ContextVk::getCommandPool() const
2607 {
2608     return mCommandPool;
2609 }
2610 
isSerialInUse(Serial serial) const2611 bool ContextVk::isSerialInUse(Serial serial) const
2612 {
2613     return serial > mLastCompletedQueueSerial;
2614 }
2615 
checkCompletedCommands()2616 angle::Result ContextVk::checkCompletedCommands()
2617 {
2618     VkDevice device = getDevice();
2619 
2620     int finishedCount = 0;
2621 
2622     for (CommandBatch &batch : mInFlightCommands)
2623     {
2624         VkResult result = batch.fence.get().getStatus(device);
2625         if (result == VK_NOT_READY)
2626         {
2627             break;
2628         }
2629         ANGLE_VK_TRY(this, result);
2630 
2631         ASSERT(batch.serial > mLastCompletedQueueSerial);
2632         mLastCompletedQueueSerial = batch.serial;
2633 
2634         mRenderer->resetSharedFence(&batch.fence);
2635         ANGLE_TRACE_EVENT0("gpu.angle", "command batch recycling");
2636         ANGLE_TRY(recycleCommandBatch(&batch));
2637         ++finishedCount;
2638     }
2639 
2640     mInFlightCommands.erase(mInFlightCommands.begin(), mInFlightCommands.begin() + finishedCount);
2641 
2642     size_t freeIndex = 0;
2643     for (; freeIndex < mGarbage.size(); ++freeIndex)
2644     {
2645         if (!mGarbage[freeIndex].destroyIfComplete(device, mLastCompletedQueueSerial))
2646             break;
2647     }
2648 
2649     // Remove the entries from the garbage list - they should be ready to go.
2650     if (freeIndex > 0)
2651     {
2652         mGarbage.erase(mGarbage.begin(), mGarbage.begin() + freeIndex);
2653     }
2654 
2655     return angle::Result::Continue;
2656 }
2657 
finishToSerial(Serial serial)2658 angle::Result ContextVk::finishToSerial(Serial serial)
2659 {
2660     bool timedOut        = false;
2661     angle::Result result = finishToSerialOrTimeout(serial, kMaxFenceWaitTimeNs, &timedOut);
2662 
2663     // Don't tolerate timeout.  If such a large wait time results in timeout, something's wrong.
2664     if (timedOut)
2665     {
2666         result = angle::Result::Stop;
2667     }
2668     return result;
2669 }
2670 
finishToSerialOrTimeout(Serial serial,uint64_t timeout,bool * outTimedOut)2671 angle::Result ContextVk::finishToSerialOrTimeout(Serial serial, uint64_t timeout, bool *outTimedOut)
2672 {
2673     *outTimedOut = false;
2674 
2675     if (!isSerialInUse(serial) || mInFlightCommands.empty())
2676     {
2677         return angle::Result::Continue;
2678     }
2679 
2680     // Find the first batch with serial equal to or bigger than given serial (note that
2681     // the batch serials are unique, otherwise upper-bound would have been necessary).
2682     size_t batchIndex = mInFlightCommands.size() - 1;
2683     for (size_t i = 0; i < mInFlightCommands.size(); ++i)
2684     {
2685         if (mInFlightCommands[i].serial >= serial)
2686         {
2687             batchIndex = i;
2688             break;
2689         }
2690     }
2691     const CommandBatch &batch = mInFlightCommands[batchIndex];
2692 
2693     // Wait for it finish
2694     VkDevice device = getDevice();
2695     VkResult status = batch.fence.get().wait(device, kMaxFenceWaitTimeNs);
2696 
2697     // If timed out, report it as such.
2698     if (status == VK_TIMEOUT)
2699     {
2700         *outTimedOut = true;
2701         return angle::Result::Continue;
2702     }
2703 
2704     ANGLE_VK_TRY(this, status);
2705 
2706     // Clean up finished batches.
2707     return checkCompletedCommands();
2708 }
2709 
getCompatibleRenderPass(const vk::RenderPassDesc & desc,vk::RenderPass ** renderPassOut)2710 angle::Result ContextVk::getCompatibleRenderPass(const vk::RenderPassDesc &desc,
2711                                                  vk::RenderPass **renderPassOut)
2712 {
2713     return mRenderPassCache.getCompatibleRenderPass(this, mCurrentQueueSerial, desc, renderPassOut);
2714 }
2715 
getRenderPassWithOps(const vk::RenderPassDesc & desc,const vk::AttachmentOpsArray & ops,vk::RenderPass ** renderPassOut)2716 angle::Result ContextVk::getRenderPassWithOps(const vk::RenderPassDesc &desc,
2717                                               const vk::AttachmentOpsArray &ops,
2718                                               vk::RenderPass **renderPassOut)
2719 {
2720     return mRenderPassCache.getRenderPassWithOps(this, mCurrentQueueSerial, desc, ops,
2721                                                  renderPassOut);
2722 }
2723 
getNextSubmitFence(vk::Shared<vk::Fence> * sharedFenceOut)2724 angle::Result ContextVk::getNextSubmitFence(vk::Shared<vk::Fence> *sharedFenceOut)
2725 {
2726     if (!mSubmitFence.isReferenced())
2727     {
2728         ANGLE_TRY(getRenderer()->newSharedFence(this, &mSubmitFence));
2729     }
2730     ASSERT(!sharedFenceOut->isReferenced());
2731     sharedFenceOut->copy(getDevice(), mSubmitFence);
2732     return angle::Result::Continue;
2733 }
2734 
getLastSubmittedFence() const2735 vk::Shared<vk::Fence> ContextVk::getLastSubmittedFence() const
2736 {
2737     vk::Shared<vk::Fence> fence;
2738     if (!mInFlightCommands.empty())
2739     {
2740         fence.copy(getDevice(), mInFlightCommands.back().fence);
2741     }
2742 
2743     return fence;
2744 }
2745 
getCommandGraph()2746 vk::CommandGraph *ContextVk::getCommandGraph()
2747 {
2748     return &mCommandGraph;
2749 }
2750 
getTimestamp(uint64_t * timestampOut)2751 angle::Result ContextVk::getTimestamp(uint64_t *timestampOut)
2752 {
2753     // The intent of this function is to query the timestamp without stalling the GPU.  Currently,
2754     // that seems impossible, so instead, we are going to make a small submission with just a
2755     // timestamp query.  First, the disjoint timer query extension says:
2756     //
2757     // > This will return the GL time after all previous commands have reached the GL server but
2758     // have not yet necessarily executed.
2759     //
2760     // The previous commands are stored in the command graph at the moment and are not yet flushed.
2761     // The wording allows us to make a submission to get the timestamp without performing a flush.
2762     //
2763     // Second:
2764     //
2765     // > By using a combination of this synchronous get command and the asynchronous timestamp query
2766     // object target, applications can measure the latency between when commands reach the GL server
2767     // and when they are realized in the framebuffer.
2768     //
2769     // This fits with the above strategy as well, although inevitably we are possibly introducing a
2770     // GPU bubble.  This function directly generates a command buffer and submits it instead of
2771     // using the other member functions.  This is to avoid changing any state, such as the queue
2772     // serial.
2773 
2774     // Create a query used to receive the GPU timestamp
2775     VkDevice device = getDevice();
2776     vk::Scoped<vk::DynamicQueryPool> timestampQueryPool(device);
2777     vk::QueryHelper timestampQuery;
2778     ANGLE_TRY(timestampQueryPool.get().init(this, VK_QUERY_TYPE_TIMESTAMP, 1));
2779     ANGLE_TRY(timestampQueryPool.get().allocateQuery(this, &timestampQuery));
2780 
2781     // Record the command buffer
2782     vk::Scoped<vk::PrimaryCommandBuffer> commandBatch(device);
2783     vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get();
2784 
2785     if (ANGLE_LIKELY(!mRenderer->getFeatures().transientCommandBuffer.enabled))
2786     {
2787         ANGLE_TRY(mPrimaryCommandPool.alloc(this, &commandBuffer));
2788     }
2789     else
2790     {
2791         VkCommandBufferAllocateInfo commandBufferInfo = {};
2792         commandBufferInfo.sType              = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
2793         commandBufferInfo.commandPool        = mCommandPool.getHandle();
2794         commandBufferInfo.level              = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
2795         commandBufferInfo.commandBufferCount = 1;
2796 
2797         ANGLE_VK_TRY(this, commandBuffer.init(device, commandBufferInfo));
2798     }
2799 
2800     VkCommandBufferBeginInfo beginInfo = {};
2801     beginInfo.sType                    = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2802     beginInfo.flags                    = 0;
2803     beginInfo.pInheritanceInfo         = nullptr;
2804 
2805     ANGLE_VK_TRY(this, commandBuffer.begin(beginInfo));
2806 
2807     commandBuffer.resetQueryPool(timestampQuery.getQueryPool()->getHandle(),
2808                                  timestampQuery.getQuery(), 1);
2809     commandBuffer.writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2810                                  timestampQuery.getQueryPool()->getHandle(),
2811                                  timestampQuery.getQuery());
2812 
2813     ANGLE_VK_TRY(this, commandBuffer.end());
2814 
2815     // Create fence for the submission
2816     VkFenceCreateInfo fenceInfo = {};
2817     fenceInfo.sType             = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2818     fenceInfo.flags             = 0;
2819 
2820     vk::Scoped<vk::Fence> fence(device);
2821     ANGLE_VK_TRY(this, fence.get().init(device, fenceInfo));
2822 
2823     // Submit the command buffer
2824     VkSubmitInfo submitInfo         = {};
2825     submitInfo.sType                = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2826     submitInfo.waitSemaphoreCount   = 0;
2827     submitInfo.pWaitSemaphores      = nullptr;
2828     submitInfo.pWaitDstStageMask    = nullptr;
2829     submitInfo.commandBufferCount   = 1;
2830     submitInfo.pCommandBuffers      = commandBuffer.ptr();
2831     submitInfo.signalSemaphoreCount = 0;
2832     submitInfo.pSignalSemaphores    = nullptr;
2833 
2834     ANGLE_TRY(getRenderer()->queueSubmit(this, submitInfo, fence.get()));
2835 
2836     // Wait for the submission to finish.  Given no semaphores, there is hope that it would execute
2837     // in parallel with what's already running on the GPU.
2838     ANGLE_VK_TRY(this, fence.get().wait(device, kMaxFenceWaitTimeNs));
2839 
2840     // Get the query results
2841     constexpr VkQueryResultFlags queryFlags = VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_64_BIT;
2842 
2843     ANGLE_VK_TRY(this, timestampQuery.getQueryPool()->getResults(
2844                            device, timestampQuery.getQuery(), 1, sizeof(*timestampOut),
2845                            timestampOut, sizeof(*timestampOut), queryFlags));
2846 
2847     timestampQueryPool.get().freeQuery(this, &timestampQuery);
2848 
2849     // Convert results to nanoseconds.
2850     *timestampOut = static_cast<uint64_t>(
2851         *timestampOut *
2852         static_cast<double>(getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod));
2853 
2854     if (ANGLE_LIKELY(!mRenderer->getFeatures().transientCommandBuffer.enabled))
2855     {
2856         ANGLE_TRY(mPrimaryCommandPool.collect(this, commandBatch.release()));
2857     }
2858     else
2859     {
2860         commandBatch.get().destroy(getDevice());
2861     }
2862 
2863     return angle::Result::Continue;
2864 }
2865 
invalidateDefaultAttribute(size_t attribIndex)2866 void ContextVk::invalidateDefaultAttribute(size_t attribIndex)
2867 {
2868     mDirtyDefaultAttribsMask.set(attribIndex);
2869     mGraphicsDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS);
2870 }
2871 
invalidateDefaultAttributes(const gl::AttributesMask & dirtyMask)2872 void ContextVk::invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask)
2873 {
2874     if (dirtyMask.any())
2875     {
2876         mDirtyDefaultAttribsMask |= dirtyMask;
2877         mGraphicsDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS);
2878     }
2879 }
2880 
updateDefaultAttribute(size_t attribIndex)2881 angle::Result ContextVk::updateDefaultAttribute(size_t attribIndex)
2882 {
2883     vk::DynamicBuffer &defaultBuffer = mDefaultAttribBuffers[attribIndex];
2884 
2885     defaultBuffer.releaseInFlightBuffers(this);
2886 
2887     uint8_t *ptr;
2888     VkBuffer bufferHandle = VK_NULL_HANDLE;
2889     VkDeviceSize offset   = 0;
2890     ANGLE_TRY(
2891         defaultBuffer.allocate(this, kDefaultValueSize, &ptr, &bufferHandle, &offset, nullptr));
2892 
2893     const gl::State &glState = mState;
2894     const gl::VertexAttribCurrentValueData &defaultValue =
2895         glState.getVertexAttribCurrentValues()[attribIndex];
2896     memcpy(ptr, &defaultValue.Values, kDefaultValueSize);
2897 
2898     ANGLE_TRY(defaultBuffer.flush(this));
2899 
2900     mVertexArray->updateDefaultAttrib(this, attribIndex, bufferHandle,
2901                                       static_cast<uint32_t>(offset));
2902     return angle::Result::Continue;
2903 }
2904 
waitForSwapchainImageIfNecessary()2905 void ContextVk::waitForSwapchainImageIfNecessary()
2906 {
2907     if (mCurrentWindowSurface)
2908     {
2909         vk::Semaphore waitSemaphore = mCurrentWindowSurface->getAcquireImageSemaphore();
2910         if (waitSemaphore.valid())
2911         {
2912             addWaitSemaphore(waitSemaphore.getHandle());
2913             releaseObject(getCurrentQueueSerial(), &waitSemaphore);
2914         }
2915     }
2916 }
2917 
getDriverUniformsDescriptorSetDesc(VkShaderStageFlags shaderStages) const2918 vk::DescriptorSetLayoutDesc ContextVk::getDriverUniformsDescriptorSetDesc(
2919     VkShaderStageFlags shaderStages) const
2920 {
2921     vk::DescriptorSetLayoutDesc desc;
2922     desc.update(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, shaderStages);
2923     return desc;
2924 }
2925 
shouldEmulateSeamfulCubeMapSampling(bool * useSubgroupOpsOut) const2926 bool ContextVk::shouldEmulateSeamfulCubeMapSampling(bool *useSubgroupOpsOut) const
2927 {
2928     // Only allow seamful cube map sampling in non-webgl ES2.
2929     if (mState.getClientMajorVersion() != 2 || mState.isWebGL())
2930     {
2931         return false;
2932     }
2933 
2934     if (mRenderer->getFeatures().disallowSeamfulCubeMapEmulation.enabled)
2935     {
2936         return false;
2937     }
2938 
2939     // Use subgroup ops where available.
2940     constexpr VkSubgroupFeatureFlags kSeamfulCubeMapSubgroupOperations =
2941         VK_SUBGROUP_FEATURE_BASIC_BIT | VK_SUBGROUP_FEATURE_BALLOT_BIT |
2942         VK_SUBGROUP_FEATURE_QUAD_BIT;
2943     const VkSubgroupFeatureFlags deviceSupportedOperations =
2944         mRenderer->getPhysicalDeviceSubgroupProperties().supportedOperations;
2945     *useSubgroupOpsOut = (deviceSupportedOperations & kSeamfulCubeMapSubgroupOperations) ==
2946                          kSeamfulCubeMapSubgroupOperations;
2947 
2948     return true;
2949 }
2950 }  // namespace rx
2951