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, ×tampQuery));
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, ×tampQuery);
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(×tamp);
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, ×tampQuery));
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, ×tampQuery);
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