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