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