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/Display.h"
17 #include "libANGLE/Program.h"
18 #include "libANGLE/Semaphore.h"
19 #include "libANGLE/Surface.h"
20 #include "libANGLE/angletypes.h"
21 #include "libANGLE/renderer/renderer_utils.h"
22 #include "libANGLE/renderer/vulkan/BufferVk.h"
23 #include "libANGLE/renderer/vulkan/CompilerVk.h"
24 #include "libANGLE/renderer/vulkan/DisplayVk.h"
25 #include "libANGLE/renderer/vulkan/FenceNVVk.h"
26 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
27 #include "libANGLE/renderer/vulkan/MemoryObjectVk.h"
28 #include "libANGLE/renderer/vulkan/OverlayVk.h"
29 #include "libANGLE/renderer/vulkan/ProgramPipelineVk.h"
30 #include "libANGLE/renderer/vulkan/ProgramVk.h"
31 #include "libANGLE/renderer/vulkan/QueryVk.h"
32 #include "libANGLE/renderer/vulkan/RenderbufferVk.h"
33 #include "libANGLE/renderer/vulkan/RendererVk.h"
34 #include "libANGLE/renderer/vulkan/SamplerVk.h"
35 #include "libANGLE/renderer/vulkan/SemaphoreVk.h"
36 #include "libANGLE/renderer/vulkan/ShaderVk.h"
37 #include "libANGLE/renderer/vulkan/SurfaceVk.h"
38 #include "libANGLE/renderer/vulkan/SyncVk.h"
39 #include "libANGLE/renderer/vulkan/TextureVk.h"
40 #include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
41 #include "libANGLE/renderer/vulkan/VertexArrayVk.h"
42
43 #include "libANGLE/trace.h"
44
45 #include <iostream>
46
47 namespace rx
48 {
49
50 namespace
51 {
52 // For DesciptorSetUpdates
53 constexpr size_t kDescriptorBufferInfosInitialSize = 8;
54 constexpr size_t kDescriptorImageInfosInitialSize = 4;
55 constexpr size_t kDescriptorWriteInfosInitialSize =
56 kDescriptorBufferInfosInitialSize + kDescriptorImageInfosInitialSize;
57
58 // For shader uniforms such as gl_DepthRange and the viewport size.
59 struct GraphicsDriverUniforms
60 {
61 std::array<float, 4> viewport;
62
63 // 32 bits for 32 clip planes
64 uint32_t enabledClipPlanes;
65
66 uint32_t xfbActiveUnpaused;
67 int32_t xfbVerticesPerInstance;
68
69 // Used to replace gl_NumSamples. Because gl_NumSamples cannot be recognized in SPIR-V.
70 int32_t numSamples;
71
72 std::array<int32_t, 4> xfbBufferOffsets;
73
74 // .xy contain packed 8-bit values for atomic counter buffer offsets. These offsets are
75 // within Vulkan's minStorageBufferOffsetAlignment limit and are used to support unaligned
76 // offsets allowed in GL.
77 //
78 // .zw are unused.
79 std::array<uint32_t, 4> acbBufferOffsets;
80
81 // We'll use x, y, z for near / far / diff respectively.
82 std::array<float, 4> depthRange;
83 };
84 static_assert(sizeof(GraphicsDriverUniforms) % (sizeof(uint32_t) * 4) == 0,
85 "GraphicsDriverUniforms should 16bytes aligned");
86
87 // TODO: http://issuetracker.google.com/173636783 Once the bug is fixed, we should remove this.
88 struct GraphicsDriverUniformsExtended
89 {
90 GraphicsDriverUniforms common;
91
92 // Used to flip gl_FragCoord (both .xy for Android pre-rotation; only .y for desktop)
93 std::array<float, 2> halfRenderArea;
94 std::array<float, 2> flipXY;
95 std::array<float, 2> negFlipXY;
96 std::array<int32_t, 2> padding;
97
98 // Used to pre-rotate gl_FragCoord for swapchain images on Android (a mat2, which is padded to
99 // the size of two vec4's).
100 std::array<float, 8> fragRotation;
101 };
102
103 struct ComputeDriverUniforms
104 {
105 // Atomic counter buffer offsets with the same layout as in GraphicsDriverUniforms.
106 std::array<uint32_t, 4> acbBufferOffsets;
107 };
108
DefaultGLErrorCode(VkResult result)109 GLenum DefaultGLErrorCode(VkResult result)
110 {
111 switch (result)
112 {
113 case VK_ERROR_OUT_OF_HOST_MEMORY:
114 case VK_ERROR_OUT_OF_DEVICE_MEMORY:
115 case VK_ERROR_TOO_MANY_OBJECTS:
116 return GL_OUT_OF_MEMORY;
117 default:
118 return GL_INVALID_OPERATION;
119 }
120 }
121
122 constexpr gl::ShaderMap<vk::ImageLayout> kShaderReadOnlyImageLayouts = {
123 {gl::ShaderType::Vertex, vk::ImageLayout::VertexShaderReadOnly},
124 {gl::ShaderType::TessControl, vk::ImageLayout::PreFragmentShadersReadOnly},
125 {gl::ShaderType::TessEvaluation, vk::ImageLayout::PreFragmentShadersReadOnly},
126 {gl::ShaderType::Geometry, vk::ImageLayout::PreFragmentShadersReadOnly},
127 {gl::ShaderType::Fragment, vk::ImageLayout::FragmentShaderReadOnly},
128 {gl::ShaderType::Compute, vk::ImageLayout::ComputeShaderReadOnly}};
129
130 constexpr gl::ShaderMap<vk::ImageLayout> kShaderWriteImageLayouts = {
131 {gl::ShaderType::Vertex, vk::ImageLayout::VertexShaderWrite},
132 {gl::ShaderType::TessControl, vk::ImageLayout::PreFragmentShadersWrite},
133 {gl::ShaderType::TessEvaluation, vk::ImageLayout::PreFragmentShadersWrite},
134 {gl::ShaderType::Geometry, vk::ImageLayout::PreFragmentShadersWrite},
135 {gl::ShaderType::Fragment, vk::ImageLayout::FragmentShaderWrite},
136 {gl::ShaderType::Compute, vk::ImageLayout::ComputeShaderWrite}};
137
138 constexpr VkBufferUsageFlags kVertexBufferUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
139 constexpr size_t kDefaultValueSize = sizeof(gl::VertexAttribCurrentValueData::Values);
140 constexpr size_t kDefaultBufferSize = kDefaultValueSize * 16;
141 constexpr size_t kDriverUniformsAllocatorPageSize = 4 * 1024;
142
GetCoverageSampleCount(const gl::State & glState,FramebufferVk * drawFramebuffer)143 uint32_t GetCoverageSampleCount(const gl::State &glState, FramebufferVk *drawFramebuffer)
144 {
145 if (!glState.isSampleCoverageEnabled())
146 {
147 return 0;
148 }
149
150 // Get a fraction of the samples based on the coverage parameters.
151 // There are multiple ways to obtain an integer value from a float -
152 // truncation, ceil and round
153 //
154 // round() provides a more even distribution of values but doesn't seem to play well
155 // with all vendors (AMD). A way to work around this is to increase the comparison threshold
156 // of deqp tests. Though this takes care of deqp tests other apps would still have issues.
157 //
158 // Truncation provides an uneven distribution near the edges of the interval but seems to
159 // play well with all vendors.
160 //
161 // We are going with truncation for expediency.
162 return static_cast<uint32_t>(glState.getSampleCoverageValue() * drawFramebuffer->getSamples());
163 }
164
ApplySampleCoverage(const gl::State & glState,uint32_t coverageSampleCount,uint32_t maskNumber,uint32_t * maskOut)165 void ApplySampleCoverage(const gl::State &glState,
166 uint32_t coverageSampleCount,
167 uint32_t maskNumber,
168 uint32_t *maskOut)
169 {
170 if (!glState.isSampleCoverageEnabled())
171 {
172 return;
173 }
174
175 uint32_t maskBitOffset = maskNumber * 32;
176 uint32_t coverageMask = coverageSampleCount >= (maskBitOffset + 32)
177 ? std::numeric_limits<uint32_t>::max()
178 : (1u << (coverageSampleCount - maskBitOffset)) - 1;
179
180 if (glState.getSampleCoverageInvert())
181 {
182 coverageMask = ~coverageMask;
183 }
184
185 *maskOut &= coverageMask;
186 }
187
IsRenderPassStartedAndUsesImage(const vk::CommandBufferHelper & renderPassCommands,const vk::ImageHelper & image)188 bool IsRenderPassStartedAndUsesImage(const vk::CommandBufferHelper &renderPassCommands,
189 const vk::ImageHelper &image)
190 {
191 return renderPassCommands.started() && renderPassCommands.usesImageInRenderPass(image);
192 }
193
194 // When an Android surface is rotated differently than the device's native orientation, ANGLE must
195 // rotate gl_Position in the last pre-rasterization shader and gl_FragCoord in the fragment shader.
196 // Rotation of gl_Position is done in SPIR-V. The following are the rotation matrices for the
197 // fragment shader.
198 //
199 // Note: these are mat2's that are appropriately padded (4 floats per row).
200 using PreRotationMatrixValues = std::array<float, 8>;
201 constexpr angle::PackedEnumMap<rx::SurfaceRotation,
202 PreRotationMatrixValues,
203 angle::EnumSize<rx::SurfaceRotation>()>
204 kFragRotationMatrices = {
205 {{rx::SurfaceRotation::Identity, {{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
206 {rx::SurfaceRotation::Rotated90Degrees,
207 {{0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}},
208 {rx::SurfaceRotation::Rotated180Degrees,
209 {{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
210 {rx::SurfaceRotation::Rotated270Degrees,
211 {{0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}},
212 {rx::SurfaceRotation::FlippedIdentity, {{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
213 {rx::SurfaceRotation::FlippedRotated90Degrees,
214 {{0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}},
215 {rx::SurfaceRotation::FlippedRotated180Degrees,
216 {{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
217 {rx::SurfaceRotation::FlippedRotated270Degrees,
218 {{0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}}}};
219
IsRotatedAspectRatio(SurfaceRotation rotation)220 bool IsRotatedAspectRatio(SurfaceRotation rotation)
221 {
222 return ((rotation == SurfaceRotation::Rotated90Degrees) ||
223 (rotation == SurfaceRotation::Rotated270Degrees) ||
224 (rotation == SurfaceRotation::FlippedRotated90Degrees) ||
225 (rotation == SurfaceRotation::FlippedRotated270Degrees));
226 }
227
DetermineSurfaceRotation(gl::Framebuffer * framebuffer,WindowSurfaceVk * windowSurface)228 SurfaceRotation DetermineSurfaceRotation(gl::Framebuffer *framebuffer,
229 WindowSurfaceVk *windowSurface)
230 {
231 if (windowSurface && framebuffer->isDefault())
232 {
233 switch (windowSurface->getPreTransform())
234 {
235 case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
236 // Do not rotate gl_Position (surface matches the device's orientation):
237 return SurfaceRotation::Identity;
238 case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
239 // Rotate gl_Position 90 degrees:
240 return SurfaceRotation::Rotated90Degrees;
241 case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
242 // Rotate gl_Position 180 degrees:
243 return SurfaceRotation::Rotated180Degrees;
244 case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
245 // Rotate gl_Position 270 degrees:
246 return SurfaceRotation::Rotated270Degrees;
247 default:
248 UNREACHABLE();
249 return SurfaceRotation::Identity;
250 }
251 }
252 else
253 {
254 // Do not rotate gl_Position (offscreen framebuffer):
255 return SurfaceRotation::Identity;
256 }
257 }
258
259 // Should not generate a copy with modern C++.
GetTraceEventName(const char * title,uint32_t counter)260 EventName GetTraceEventName(const char *title, uint32_t counter)
261 {
262 EventName buf;
263 snprintf(buf.data(), kMaxGpuEventNameLen - 1, "%s %u", title, counter);
264 return buf;
265 }
266
GetDepthAccess(const gl::DepthStencilState & dsState)267 vk::ResourceAccess GetDepthAccess(const gl::DepthStencilState &dsState)
268 {
269 if (!dsState.depthTest)
270 {
271 return vk::ResourceAccess::Unused;
272 }
273 return dsState.isDepthMaskedOut() ? vk::ResourceAccess::ReadOnly : vk::ResourceAccess::Write;
274 }
275
GetStencilAccess(const gl::DepthStencilState & dsState)276 vk::ResourceAccess GetStencilAccess(const gl::DepthStencilState &dsState)
277 {
278 if (!dsState.stencilTest)
279 {
280 return vk::ResourceAccess::Unused;
281 }
282
283 return dsState.isStencilNoOp() && dsState.isStencilBackNoOp() ? vk::ResourceAccess::ReadOnly
284 : vk::ResourceAccess::Write;
285 }
286
GetContextPriority(const gl::State & state)287 egl::ContextPriority GetContextPriority(const gl::State &state)
288 {
289 return egl::FromEGLenum<egl::ContextPriority>(state.getContextPriority());
290 }
291
292 template <typename MaskT>
AppendBufferVectorToDesc(vk::ShaderBuffersDescriptorDesc * desc,const gl::BufferVector & buffers,const MaskT & buffersMask,bool appendOffset)293 void AppendBufferVectorToDesc(vk::ShaderBuffersDescriptorDesc *desc,
294 const gl::BufferVector &buffers,
295 const MaskT &buffersMask,
296 bool appendOffset)
297 {
298 if (buffersMask.any())
299 {
300 typename MaskT::param_type lastBufferIndex = buffersMask.last();
301 for (typename MaskT::param_type bufferIndex = 0; bufferIndex <= lastBufferIndex;
302 ++bufferIndex)
303 {
304 const gl::OffsetBindingPointer<gl::Buffer> &binding = buffers[bufferIndex];
305 const gl::Buffer *bufferGL = binding.get();
306
307 if (!bufferGL)
308 {
309 desc->append32BitValue(0);
310 continue;
311 }
312
313 BufferVk *bufferVk = vk::GetImpl(bufferGL);
314
315 if (!bufferVk->isBufferValid())
316 {
317 desc->append32BitValue(0);
318 continue;
319 }
320
321 VkDeviceSize bufferOffset = 0;
322 vk::BufferSerial bufferSerial =
323 bufferVk->getBufferAndOffset(&bufferOffset).getBufferSerial();
324
325 desc->appendBufferSerial(bufferSerial);
326 ASSERT(static_cast<uint64_t>(binding.getSize()) <=
327 static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()));
328 desc->append32BitValue(static_cast<uint32_t>(binding.getSize()));
329 if (appendOffset)
330 {
331 ASSERT(static_cast<uint64_t>(binding.getOffset()) <
332 static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()));
333 desc->append32BitValue(static_cast<uint32_t>(bufferOffset + binding.getOffset()));
334 }
335 }
336 }
337
338 desc->append32BitValue(std::numeric_limits<uint32_t>::max());
339 }
340 } // anonymous namespace
341
342 // Not necessary once upgraded to C++17.
343 constexpr ContextVk::DirtyBits ContextVk::kIndexAndVertexDirtyBits;
344 constexpr ContextVk::DirtyBits ContextVk::kPipelineDescAndBindingDirtyBits;
345 constexpr ContextVk::DirtyBits ContextVk::kTexturesAndDescSetDirtyBits;
346 constexpr ContextVk::DirtyBits ContextVk::kResourcesAndDescSetDirtyBits;
347 constexpr ContextVk::DirtyBits ContextVk::kXfbBuffersAndDescSetDirtyBits;
348 constexpr ContextVk::DirtyBits ContextVk::kDriverUniformsAndBindingDirtyBits;
349
flushDescriptorSetUpdates()350 ANGLE_INLINE void ContextVk::flushDescriptorSetUpdates()
351 {
352 if (mWriteDescriptorSets.empty())
353 {
354 ASSERT(mDescriptorBufferInfos.empty());
355 ASSERT(mDescriptorImageInfos.empty());
356 return;
357 }
358
359 vkUpdateDescriptorSets(getDevice(), static_cast<uint32_t>(mWriteDescriptorSets.size()),
360 mWriteDescriptorSets.data(), 0, nullptr);
361 mWriteDescriptorSets.clear();
362 mDescriptorBufferInfos.clear();
363 mDescriptorImageInfos.clear();
364 }
365
onRenderPassFinished()366 ANGLE_INLINE void ContextVk::onRenderPassFinished()
367 {
368 pauseRenderPassQueriesIfActive();
369
370 mRenderPassCommandBuffer = nullptr;
371 mGraphicsDirtyBits.set(DIRTY_BIT_RENDER_PASS);
372 }
373
374 // ContextVk::ScopedDescriptorSetUpdates implementation.
375 class ContextVk::ScopedDescriptorSetUpdates final : angle::NonCopyable
376 {
377 public:
ScopedDescriptorSetUpdates(ContextVk * contextVk)378 ANGLE_INLINE ScopedDescriptorSetUpdates(ContextVk *contextVk) : mContextVk(contextVk) {}
~ScopedDescriptorSetUpdates()379 ANGLE_INLINE ~ScopedDescriptorSetUpdates() { mContextVk->flushDescriptorSetUpdates(); }
380
381 private:
382 ContextVk *mContextVk;
383 };
384
DriverUniformsDescriptorSet()385 ContextVk::DriverUniformsDescriptorSet::DriverUniformsDescriptorSet()
386 : descriptorSet(VK_NULL_HANDLE), dynamicOffset(0)
387 {}
388
389 ContextVk::DriverUniformsDescriptorSet::~DriverUniformsDescriptorSet() = default;
390
init(RendererVk * rendererVk)391 void ContextVk::DriverUniformsDescriptorSet::init(RendererVk *rendererVk)
392 {
393 size_t minAlignment = static_cast<size_t>(
394 rendererVk->getPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment);
395 dynamicBuffer.init(rendererVk, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, minAlignment,
396 kDriverUniformsAllocatorPageSize, true,
397 vk::DynamicBufferPolicy::FrequentSmallAllocations);
398 descriptorSetCache.clear();
399 }
400
destroy(RendererVk * renderer)401 void ContextVk::DriverUniformsDescriptorSet::destroy(RendererVk *renderer)
402 {
403 descriptorSetLayout.reset();
404 descriptorPoolBinding.reset();
405 dynamicBuffer.destroy(renderer);
406 descriptorSetCache.clear();
407 descriptorSetCache.destroy(renderer);
408 }
409
410 // ContextVk implementation.
ContextVk(const gl::State & state,gl::ErrorSet * errorSet,RendererVk * renderer)411 ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk *renderer)
412 : ContextImpl(state, errorSet),
413 vk::Context(renderer),
414 mGraphicsDirtyBitHandlers{},
415 mComputeDirtyBitHandlers{},
416 mRenderPassCommandBuffer(nullptr),
417 mCurrentGraphicsPipeline(nullptr),
418 mCurrentComputePipeline(nullptr),
419 mCurrentDrawMode(gl::PrimitiveMode::InvalidEnum),
420 mCurrentWindowSurface(nullptr),
421 mCurrentRotationDrawFramebuffer(SurfaceRotation::Identity),
422 mCurrentRotationReadFramebuffer(SurfaceRotation::Identity),
423 mActiveRenderPassQueries{},
424 mVertexArray(nullptr),
425 mDrawFramebuffer(nullptr),
426 mProgram(nullptr),
427 mExecutable(nullptr),
428 mLastIndexBufferOffset(nullptr),
429 mCurrentIndexBufferOffset(0),
430 mCurrentDrawElementsType(gl::DrawElementsType::InvalidEnum),
431 mXfbBaseVertex(0),
432 mXfbVertexCountPerInstance(0),
433 mClearColorValue{},
434 mClearDepthStencilValue{},
435 mClearColorMasks(0),
436 mFlipYForCurrentSurface(false),
437 mFlipViewportForDrawFramebuffer(false),
438 mFlipViewportForReadFramebuffer(false),
439 mIsAnyHostVisibleBufferWritten(false),
440 mEmulateSeamfulCubeMapSampling(false),
441 mOutsideRenderPassCommands(nullptr),
442 mRenderPassCommands(nullptr),
443 mQueryEventType(GraphicsEventCmdBuf::NotInQueryCmd),
444 mGpuEventsEnabled(false),
445 mEGLSyncObjectPendingFlush(false),
446 mHasDeferredFlush(false),
447 mLastProgramUsesFramebufferFetch(false),
448 mGpuClockSync{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()},
449 mGpuEventTimestampOrigin(0),
450 mPerfCounters{},
451 mContextPerfCounters{},
452 mCumulativeContextPerfCounters{},
453 mContextPriority(renderer->getDriverPriority(GetContextPriority(state))),
454 mShareGroupVk(vk::GetImpl(state.getShareGroup()))
455 {
456 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::ContextVk");
457 memset(&mClearColorValue, 0, sizeof(mClearColorValue));
458 memset(&mClearDepthStencilValue, 0, sizeof(mClearDepthStencilValue));
459 memset(&mViewport, 0, sizeof(mViewport));
460 memset(&mScissor, 0, sizeof(mScissor));
461
462 // Ensure viewport is within Vulkan requirements
463 vk::ClampViewport(&mViewport);
464
465 mNonIndexedDirtyBitsMask.set();
466 mNonIndexedDirtyBitsMask.reset(DIRTY_BIT_INDEX_BUFFER);
467
468 mIndexedDirtyBitsMask.set();
469
470 // Once a command buffer is ended, all bindings (through |vkCmdBind*| calls) are lost per Vulkan
471 // spec. Once a new command buffer is allocated, we must make sure every previously bound
472 // resource is bound again.
473 //
474 // Note that currently these dirty bits are set every time a new render pass command buffer is
475 // begun. However, using ANGLE's SecondaryCommandBuffer, the Vulkan command buffer (which is
476 // the primary command buffer) is not ended, so technically we don't need to rebind these.
477 mNewGraphicsCommandBufferDirtyBits =
478 DirtyBits{DIRTY_BIT_RENDER_PASS, DIRTY_BIT_PIPELINE_BINDING,
479 DIRTY_BIT_TEXTURES, DIRTY_BIT_VERTEX_BUFFERS,
480 DIRTY_BIT_INDEX_BUFFER, DIRTY_BIT_SHADER_RESOURCES,
481 DIRTY_BIT_DESCRIPTOR_SETS, DIRTY_BIT_DRIVER_UNIFORMS_BINDING,
482 DIRTY_BIT_VIEWPORT, DIRTY_BIT_SCISSOR};
483 if (getFeatures().supportsTransformFeedbackExtension.enabled)
484 {
485 mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
486 }
487
488 mNewComputeCommandBufferDirtyBits =
489 DirtyBits{DIRTY_BIT_PIPELINE_BINDING, DIRTY_BIT_TEXTURES, DIRTY_BIT_SHADER_RESOURCES,
490 DIRTY_BIT_DESCRIPTOR_SETS, DIRTY_BIT_DRIVER_UNIFORMS_BINDING};
491
492 mGraphicsDirtyBitHandlers[DIRTY_BIT_MEMORY_BARRIER] =
493 &ContextVk::handleDirtyGraphicsMemoryBarrier;
494 mGraphicsDirtyBitHandlers[DIRTY_BIT_EVENT_LOG] = &ContextVk::handleDirtyGraphicsEventLog;
495 mGraphicsDirtyBitHandlers[DIRTY_BIT_DEFAULT_ATTRIBS] =
496 &ContextVk::handleDirtyGraphicsDefaultAttribs;
497 mGraphicsDirtyBitHandlers[DIRTY_BIT_PIPELINE_DESC] =
498 &ContextVk::handleDirtyGraphicsPipelineDesc;
499 mGraphicsDirtyBitHandlers[DIRTY_BIT_RENDER_PASS] = &ContextVk::handleDirtyGraphicsRenderPass;
500 mGraphicsDirtyBitHandlers[DIRTY_BIT_PIPELINE_BINDING] =
501 &ContextVk::handleDirtyGraphicsPipelineBinding;
502 mGraphicsDirtyBitHandlers[DIRTY_BIT_TEXTURES] = &ContextVk::handleDirtyGraphicsTextures;
503 mGraphicsDirtyBitHandlers[DIRTY_BIT_VERTEX_BUFFERS] =
504 &ContextVk::handleDirtyGraphicsVertexBuffers;
505 mGraphicsDirtyBitHandlers[DIRTY_BIT_INDEX_BUFFER] = &ContextVk::handleDirtyGraphicsIndexBuffer;
506 mGraphicsDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] =
507 &ContextVk::handleDirtyGraphicsDriverUniforms;
508 mGraphicsDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS_BINDING] =
509 &ContextVk::handleDirtyGraphicsDriverUniformsBinding;
510 mGraphicsDirtyBitHandlers[DIRTY_BIT_SHADER_RESOURCES] =
511 &ContextVk::handleDirtyGraphicsShaderResources;
512 mGraphicsDirtyBitHandlers[DIRTY_BIT_FRAMEBUFFER_FETCH_BARRIER] =
513 &ContextVk::handleDirtyGraphicsFramebufferFetchBarrier;
514 if (getFeatures().supportsTransformFeedbackExtension.enabled)
515 {
516 mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
517 &ContextVk::handleDirtyGraphicsTransformFeedbackBuffersExtension;
518 mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME] =
519 &ContextVk::handleDirtyGraphicsTransformFeedbackResume;
520 }
521 else if (getFeatures().emulateTransformFeedback.enabled)
522 {
523 mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
524 &ContextVk::handleDirtyGraphicsTransformFeedbackBuffersEmulation;
525 }
526
527 mGraphicsDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] =
528 &ContextVk::handleDirtyGraphicsDescriptorSets;
529
530 mGraphicsDirtyBitHandlers[DIRTY_BIT_VIEWPORT] = &ContextVk::handleDirtyGraphicsViewport;
531 mGraphicsDirtyBitHandlers[DIRTY_BIT_SCISSOR] = &ContextVk::handleDirtyGraphicsScissor;
532
533 mComputeDirtyBitHandlers[DIRTY_BIT_MEMORY_BARRIER] =
534 &ContextVk::handleDirtyComputeMemoryBarrier;
535 mComputeDirtyBitHandlers[DIRTY_BIT_EVENT_LOG] = &ContextVk::handleDirtyComputeEventLog;
536 mComputeDirtyBitHandlers[DIRTY_BIT_PIPELINE_DESC] = &ContextVk::handleDirtyComputePipelineDesc;
537 mComputeDirtyBitHandlers[DIRTY_BIT_PIPELINE_BINDING] =
538 &ContextVk::handleDirtyComputePipelineBinding;
539 mComputeDirtyBitHandlers[DIRTY_BIT_TEXTURES] = &ContextVk::handleDirtyComputeTextures;
540 mComputeDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] =
541 &ContextVk::handleDirtyComputeDriverUniforms;
542 mComputeDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS_BINDING] =
543 &ContextVk::handleDirtyComputeDriverUniformsBinding;
544 mComputeDirtyBitHandlers[DIRTY_BIT_SHADER_RESOURCES] =
545 &ContextVk::handleDirtyComputeShaderResources;
546 mComputeDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] =
547 &ContextVk::handleDirtyComputeDescriptorSets;
548
549 mGraphicsDirtyBits = mNewGraphicsCommandBufferDirtyBits;
550 mComputeDirtyBits = mNewComputeCommandBufferDirtyBits;
551
552 mActiveTextures.fill({nullptr, nullptr, true});
553 mActiveImages.fill(nullptr);
554
555 // The following dirty bits don't affect the program pipeline:
556 //
557 // - READ_FRAMEBUFFER_BINDING only affects operations that read from said framebuffer,
558 // - CLEAR_* only affect following clear calls,
559 // - PACK/UNPACK_STATE only affect texture data upload/download,
560 // - *_BINDING only affect descriptor sets.
561 //
562 mPipelineDirtyBitsMask.set();
563 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
564 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_CLEAR_COLOR);
565 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_CLEAR_DEPTH);
566 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_CLEAR_STENCIL);
567 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_UNPACK_STATE);
568 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_UNPACK_BUFFER_BINDING);
569 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_PACK_STATE);
570 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_PACK_BUFFER_BINDING);
571 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_RENDERBUFFER_BINDING);
572 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING);
573 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING);
574 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_SAMPLER_BINDINGS);
575 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_TEXTURE_BINDINGS);
576 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_IMAGE_BINDINGS);
577 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING);
578 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS);
579 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING);
580 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING);
581
582 // Reserve reasonable amount of spaces so that for majority of apps we don't need to grow at all
583 mDescriptorBufferInfos.reserve(kDescriptorBufferInfosInitialSize);
584 mDescriptorImageInfos.reserve(kDescriptorImageInfosInitialSize);
585 mWriteDescriptorSets.reserve(kDescriptorWriteInfosInitialSize);
586 }
587
588 ContextVk::~ContextVk() = default;
589
onDestroy(const gl::Context * context)590 void ContextVk::onDestroy(const gl::Context *context)
591 {
592 outputCumulativePerfCounters();
593
594 // Remove context from the share group
595 mShareGroupVk->getContexts()->erase(this);
596
597 // This will not destroy any resources. It will release them to be collected after finish.
598 mIncompleteTextures.onDestroy(context);
599
600 // Flush and complete current outstanding work before destruction.
601 (void)finishImpl();
602
603 VkDevice device = getDevice();
604
605 for (DriverUniformsDescriptorSet &driverUniforms : mDriverUniforms)
606 {
607 driverUniforms.destroy(mRenderer);
608 }
609
610 for (vk::DynamicDescriptorPool &dynamicDescriptorPool : mDriverUniformsDescriptorPools)
611 {
612 dynamicDescriptorPool.destroy(device);
613 }
614
615 mDefaultUniformStorage.release(mRenderer);
616 mEmptyBuffer.release(mRenderer);
617 mStagingBuffer.release(mRenderer);
618
619 for (vk::DynamicBuffer &defaultBuffer : mDefaultAttribBuffers)
620 {
621 defaultBuffer.destroy(mRenderer);
622 }
623
624 for (vk::DynamicQueryPool &queryPool : mQueryPools)
625 {
626 queryPool.destroy(device);
627 }
628
629 // Recycle current commands buffers.
630 mRenderer->recycleCommandBufferHelper(mOutsideRenderPassCommands);
631 mRenderer->recycleCommandBufferHelper(mRenderPassCommands);
632 mOutsideRenderPassCommands = nullptr;
633 mRenderPassCommands = nullptr;
634
635 mRenderer->releaseSharedResources(&mResourceUseList);
636
637 mUtils.destroy(mRenderer);
638
639 mRenderPassCache.destroy(mRenderer);
640 mShaderLibrary.destroy(device);
641 mGpuEventQueryPool.destroy(device);
642 mCommandPool.destroy(device);
643
644 ASSERT(mCurrentGarbage.empty());
645 ASSERT(mResourceUseList.empty());
646 }
647
getIncompleteTexture(const gl::Context * context,gl::TextureType type,gl::SamplerFormat format,gl::Texture ** textureOut)648 angle::Result ContextVk::getIncompleteTexture(const gl::Context *context,
649 gl::TextureType type,
650 gl::SamplerFormat format,
651 gl::Texture **textureOut)
652 {
653 return mIncompleteTextures.getIncompleteTexture(context, type, format, this, textureOut);
654 }
655
initialize()656 angle::Result ContextVk::initialize()
657 {
658 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::initialize");
659
660 ANGLE_TRY(mQueryPools[gl::QueryType::AnySamples].init(this, VK_QUERY_TYPE_OCCLUSION,
661 vk::kDefaultOcclusionQueryPoolSize));
662 ANGLE_TRY(mQueryPools[gl::QueryType::AnySamplesConservative].init(
663 this, VK_QUERY_TYPE_OCCLUSION, vk::kDefaultOcclusionQueryPoolSize));
664
665 // Only initialize the timestamp query pools if the extension is available.
666 if (mRenderer->getQueueFamilyProperties().timestampValidBits > 0)
667 {
668 ANGLE_TRY(mQueryPools[gl::QueryType::Timestamp].init(this, VK_QUERY_TYPE_TIMESTAMP,
669 vk::kDefaultTimestampQueryPoolSize));
670 ANGLE_TRY(mQueryPools[gl::QueryType::TimeElapsed].init(this, VK_QUERY_TYPE_TIMESTAMP,
671 vk::kDefaultTimestampQueryPoolSize));
672 }
673
674 if (getFeatures().supportsTransformFeedbackExtension.enabled)
675 {
676 ANGLE_TRY(mQueryPools[gl::QueryType::TransformFeedbackPrimitivesWritten].init(
677 this, VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT,
678 vk::kDefaultTransformFeedbackQueryPoolSize));
679 }
680
681 // The primitives generated query is provided through the Vulkan pipeline statistics query if
682 // supported. TODO: If VK_EXT_primitives_generated_query is supported, use that instead.
683 // http://anglebug.com/5430
684 if (getFeatures().supportsPipelineStatisticsQuery.enabled)
685 {
686 ANGLE_TRY(mQueryPools[gl::QueryType::PrimitivesGenerated].init(
687 this, VK_QUERY_TYPE_PIPELINE_STATISTICS, vk::kDefaultPrimitivesGeneratedQueryPoolSize));
688 }
689
690 // Init GLES to Vulkan index type map.
691 initIndexTypeMap();
692
693 // Init driver uniforms and get the descriptor set layouts.
694 constexpr angle::PackedEnumMap<PipelineType, VkShaderStageFlags> kPipelineStages = {
695 {PipelineType::Graphics, VK_SHADER_STAGE_ALL_GRAPHICS},
696 {PipelineType::Compute, VK_SHADER_STAGE_COMPUTE_BIT},
697 };
698 for (PipelineType pipeline : angle::AllEnums<PipelineType>())
699 {
700 mDriverUniforms[pipeline].init(mRenderer);
701
702 vk::DescriptorSetLayoutDesc desc =
703 getDriverUniformsDescriptorSetDesc(kPipelineStages[pipeline]);
704 ANGLE_TRY(getDescriptorSetLayoutCache().getDescriptorSetLayout(
705 this, desc, &mDriverUniforms[pipeline].descriptorSetLayout));
706
707 vk::DescriptorSetLayoutBindingVector bindingVector;
708 std::vector<VkSampler> immutableSamplers;
709 desc.unpackBindings(&bindingVector, &immutableSamplers);
710 std::vector<VkDescriptorPoolSize> descriptorPoolSizes;
711
712 for (const VkDescriptorSetLayoutBinding &binding : bindingVector)
713 {
714 if (binding.descriptorCount > 0)
715 {
716 VkDescriptorPoolSize poolSize = {};
717
718 poolSize.type = binding.descriptorType;
719 poolSize.descriptorCount = binding.descriptorCount;
720 descriptorPoolSizes.emplace_back(poolSize);
721 }
722 }
723 if (!descriptorPoolSizes.empty())
724 {
725 ANGLE_TRY(mDriverUniformsDescriptorPools[pipeline].init(
726 this, descriptorPoolSizes.data(), descriptorPoolSizes.size(),
727 mDriverUniforms[pipeline].descriptorSetLayout.get().getHandle()));
728 }
729 }
730
731 mGraphicsPipelineDesc.reset(new vk::GraphicsPipelineDesc());
732 mGraphicsPipelineDesc->initDefaults(this);
733
734 // Initialize current value/default attribute buffers.
735 for (vk::DynamicBuffer &buffer : mDefaultAttribBuffers)
736 {
737 buffer.init(mRenderer, kVertexBufferUsage, 1, kDefaultBufferSize, true,
738 vk::DynamicBufferPolicy::FrequentSmallAllocations);
739 }
740
741 #if ANGLE_ENABLE_VULKAN_GPU_TRACE_EVENTS
742 angle::PlatformMethods *platform = ANGLEPlatformCurrent();
743 ASSERT(platform);
744
745 // GPU tracing workaround for anglebug.com/2927. The renderer should not emit gpu events
746 // during platform discovery.
747 const unsigned char *gpuEventsEnabled =
748 platform->getTraceCategoryEnabledFlag(platform, "gpu.angle.gpu");
749 mGpuEventsEnabled = gpuEventsEnabled && *gpuEventsEnabled;
750 #endif
751
752 mEmulateSeamfulCubeMapSampling = shouldEmulateSeamfulCubeMapSampling();
753
754 // Assign initial command buffers from queue
755 mOutsideRenderPassCommands = mRenderer->getCommandBufferHelper(false);
756 mRenderPassCommands = mRenderer->getCommandBufferHelper(true);
757
758 if (mGpuEventsEnabled)
759 {
760 // GPU events should only be available if timestamp queries are available.
761 ASSERT(mRenderer->getQueueFamilyProperties().timestampValidBits > 0);
762 // Calculate the difference between CPU and GPU clocks for GPU event reporting.
763 ANGLE_TRY(mGpuEventQueryPool.init(this, VK_QUERY_TYPE_TIMESTAMP,
764 vk::kDefaultTimestampQueryPoolSize));
765 ANGLE_TRY(synchronizeCpuGpuTime());
766
767 mPerfCounters.primaryBuffers++;
768
769 EventName eventName = GetTraceEventName("Primary", mPerfCounters.primaryBuffers);
770 ANGLE_TRY(traceGpuEvent(&mOutsideRenderPassCommands->getCommandBuffer(),
771 TRACE_EVENT_PHASE_BEGIN, eventName));
772 }
773
774 size_t minAlignment = static_cast<size_t>(
775 mRenderer->getPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment);
776 mDefaultUniformStorage.init(mRenderer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, minAlignment,
777 mRenderer->getDefaultUniformBufferSize(), true,
778 vk::DynamicBufferPolicy::FrequentSmallAllocations);
779
780 // Initialize an "empty" buffer for use with default uniform blocks where there are no uniforms,
781 // or atomic counter buffer array indices that are unused.
782 constexpr VkBufferUsageFlags kEmptyBufferUsage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
783 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
784 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
785 VkBufferCreateInfo emptyBufferInfo = {};
786 emptyBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
787 emptyBufferInfo.flags = 0;
788 emptyBufferInfo.size = 16;
789 emptyBufferInfo.usage = kEmptyBufferUsage;
790 emptyBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
791 emptyBufferInfo.queueFamilyIndexCount = 0;
792 emptyBufferInfo.pQueueFamilyIndices = nullptr;
793 constexpr VkMemoryPropertyFlags kMemoryType = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
794 ANGLE_TRY(mEmptyBuffer.init(this, emptyBufferInfo, kMemoryType));
795
796 constexpr VkImageUsageFlags kStagingBufferUsageFlags =
797 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
798 size_t stagingBufferAlignment =
799 static_cast<size_t>(mRenderer->getPhysicalDeviceProperties().limits.minMemoryMapAlignment);
800 constexpr size_t kStagingBufferSize = 1024u * 1024u; // 1M
801 mStagingBuffer.init(mRenderer, kStagingBufferUsageFlags, stagingBufferAlignment,
802 kStagingBufferSize, true, vk::DynamicBufferPolicy::SporadicTextureUpload);
803
804 // Add context into the share group
805 mShareGroupVk->getContexts()->insert(this);
806
807 return angle::Result::Continue;
808 }
809
flush(const gl::Context * context)810 angle::Result ContextVk::flush(const gl::Context *context)
811 {
812 // If a sync object has been used or this is a shared context, then we need to flush the
813 // commands and end the render pass to make sure the sync object (and any preceding commands)
814 // lands in the correct place within the command stream.
815 // EGL sync objects can span across context share groups, so don't defer flushes if there's one
816 // pending a flush.
817 if (getShareGroupVk()->isSyncObjectPendingFlush() && context->isShared() &&
818 !mEGLSyncObjectPendingFlush)
819 {
820 // Flush the commands to create a sync point in the command stream.
821 ANGLE_TRY(flushCommandsAndEndRenderPass());
822 // Move the resources to the share group, so they are released during the next vkQueueSubmit
823 // performed by any context in the share group. Note that this relies heavily on the global
824 // mutex to guarantee that no two contexts are modifying the lists at the same time.
825 getShareGroupVk()->acquireResourceUseList(std::move(mResourceUseList));
826 mHasDeferredFlush = true;
827 return angle::Result::Continue;
828 }
829
830 // EGL sync objects can span across context share groups, so don't defer flushes if there's one
831 // pending a flush.
832 if (!mEGLSyncObjectPendingFlush &&
833 mRenderer->getFeatures().deferFlushUntilEndRenderPass.enabled && hasStartedRenderPass())
834 {
835 mHasDeferredFlush = true;
836 return angle::Result::Continue;
837 }
838
839 return flushImpl(nullptr);
840 }
841
finish(const gl::Context * context)842 angle::Result ContextVk::finish(const gl::Context *context)
843 {
844 return finishImpl();
845 }
846
setupDraw(const gl::Context * context,gl::PrimitiveMode mode,GLint firstVertexOrInvalid,GLsizei vertexOrIndexCount,GLsizei instanceCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,DirtyBits dirtyBitMask)847 angle::Result ContextVk::setupDraw(const gl::Context *context,
848 gl::PrimitiveMode mode,
849 GLint firstVertexOrInvalid,
850 GLsizei vertexOrIndexCount,
851 GLsizei instanceCount,
852 gl::DrawElementsType indexTypeOrInvalid,
853 const void *indices,
854 DirtyBits dirtyBitMask)
855 {
856 // Set any dirty bits that depend on draw call parameters or other objects.
857 if (mode != mCurrentDrawMode)
858 {
859 invalidateCurrentGraphicsPipeline();
860 mCurrentDrawMode = mode;
861 mGraphicsPipelineDesc->updateTopology(&mGraphicsPipelineTransition, mCurrentDrawMode);
862 }
863
864 // Must be called before the command buffer is started. Can call finish.
865 if (mVertexArray->getStreamingVertexAttribsMask().any())
866 {
867 // All client attribs & any emulated buffered attribs will be updated
868 ANGLE_TRY(mVertexArray->updateStreamedAttribs(context, firstVertexOrInvalid,
869 vertexOrIndexCount, instanceCount,
870 indexTypeOrInvalid, indices));
871
872 mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
873 }
874
875 // Create a local object to ensure we flush the descriptor updates to device when we leave this
876 // function
877 ScopedDescriptorSetUpdates descriptorSetUpdates(this);
878
879 if (mProgram && mProgram->dirtyUniforms())
880 {
881 ANGLE_TRY(mProgram->updateUniforms(this));
882 mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
883 }
884 else if (mProgramPipeline && mProgramPipeline->dirtyUniforms(getState()))
885 {
886 ANGLE_TRY(mProgramPipeline->updateUniforms(this));
887 mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
888 }
889
890 // Update transform feedback offsets on every draw call when emulating transform feedback. This
891 // relies on the fact that no geometry/tessellation, indirect or indexed calls are supported in
892 // ES3.1 (and emulation is not done for ES3.2).
893 if (getFeatures().emulateTransformFeedback.enabled &&
894 mState.isTransformFeedbackActiveUnpaused())
895 {
896 ASSERT(firstVertexOrInvalid != -1);
897 mXfbBaseVertex = firstVertexOrInvalid;
898 mXfbVertexCountPerInstance = vertexOrIndexCount;
899 invalidateGraphicsDriverUniforms();
900 }
901
902 DirtyBits dirtyBits = mGraphicsDirtyBits & dirtyBitMask;
903
904 if (dirtyBits.none())
905 {
906 ASSERT(mRenderPassCommandBuffer);
907 return angle::Result::Continue;
908 }
909
910 // Flush any relevant dirty bits.
911 for (DirtyBits::Iterator dirtyBitIter = dirtyBits.begin(); dirtyBitIter != dirtyBits.end();
912 ++dirtyBitIter)
913 {
914 ASSERT(mGraphicsDirtyBitHandlers[*dirtyBitIter]);
915 ANGLE_TRY((this->*mGraphicsDirtyBitHandlers[*dirtyBitIter])(&dirtyBitIter, dirtyBitMask));
916 }
917
918 mGraphicsDirtyBits &= ~dirtyBitMask;
919
920 // Render pass must be always available at this point.
921 ASSERT(mRenderPassCommandBuffer);
922
923 return angle::Result::Continue;
924 }
925
setupIndexedDraw(const gl::Context * context,gl::PrimitiveMode mode,GLsizei indexCount,GLsizei instanceCount,gl::DrawElementsType indexType,const void * indices)926 angle::Result ContextVk::setupIndexedDraw(const gl::Context *context,
927 gl::PrimitiveMode mode,
928 GLsizei indexCount,
929 GLsizei instanceCount,
930 gl::DrawElementsType indexType,
931 const void *indices)
932 {
933 ASSERT(mode != gl::PrimitiveMode::LineLoop);
934
935 if (indexType != mCurrentDrawElementsType)
936 {
937 mCurrentDrawElementsType = indexType;
938 ANGLE_TRY(onIndexBufferChange(nullptr));
939 }
940
941 const gl::Buffer *elementArrayBuffer = mVertexArray->getState().getElementArrayBuffer();
942 if (!elementArrayBuffer)
943 {
944 mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
945 ANGLE_TRY(mVertexArray->convertIndexBufferCPU(this, indexType, indexCount, indices));
946 mCurrentIndexBufferOffset = 0;
947 }
948 else
949 {
950 mCurrentIndexBufferOffset = reinterpret_cast<VkDeviceSize>(indices);
951
952 if (indices != mLastIndexBufferOffset)
953 {
954 mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
955 mLastIndexBufferOffset = indices;
956 }
957 if (shouldConvertUint8VkIndexType(indexType) && mGraphicsDirtyBits[DIRTY_BIT_INDEX_BUFFER])
958 {
959 ANGLE_PERF_WARNING(getDebug(), GL_DEBUG_SEVERITY_LOW,
960 "Potential inefficiency emulating uint8 vertex attributes due to "
961 "lack of hardware support");
962
963 BufferVk *bufferVk = vk::GetImpl(elementArrayBuffer);
964 VkDeviceSize bufferOffset = 0;
965 vk::BufferHelper &bufferHelper = bufferVk->getBufferAndOffset(&bufferOffset);
966
967 if (bufferHelper.isHostVisible() &&
968 !bufferHelper.isCurrentlyInUse(getLastCompletedQueueSerial()))
969 {
970 uint8_t *src = nullptr;
971 ANGLE_TRY(bufferVk->mapImpl(this, reinterpret_cast<void **>(&src)));
972 // Note: bufferOffset is not added here because mapImpl already adds it.
973 src += reinterpret_cast<uintptr_t>(indices);
974 const size_t byteCount = static_cast<size_t>(elementArrayBuffer->getSize()) -
975 reinterpret_cast<uintptr_t>(indices);
976 ANGLE_TRY(mVertexArray->convertIndexBufferCPU(this, indexType, byteCount, src));
977 ANGLE_TRY(bufferVk->unmapImpl(this));
978 }
979 else
980 {
981 ANGLE_TRY(mVertexArray->convertIndexBufferGPU(this, bufferVk, indices));
982 }
983
984 mCurrentIndexBufferOffset = 0;
985 }
986 }
987
988 return setupDraw(context, mode, 0, indexCount, instanceCount, indexType, indices,
989 mIndexedDirtyBitsMask);
990 }
991
setupIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,DirtyBits dirtyBitMask,vk::BufferHelper * indirectBuffer,VkDeviceSize indirectBufferOffset)992 angle::Result ContextVk::setupIndirectDraw(const gl::Context *context,
993 gl::PrimitiveMode mode,
994 DirtyBits dirtyBitMask,
995 vk::BufferHelper *indirectBuffer,
996 VkDeviceSize indirectBufferOffset)
997 {
998 GLint firstVertex = -1;
999 GLsizei vertexCount = 0;
1000 GLsizei instanceCount = 1;
1001
1002 // Break the render pass if the indirect buffer was previously used as the output from transform
1003 // feedback.
1004 if (mCurrentTransformFeedbackBuffers.contains(indirectBuffer))
1005 {
1006 ANGLE_TRY(flushCommandsAndEndRenderPass());
1007 }
1008
1009 ANGLE_TRY(setupDraw(context, mode, firstVertex, vertexCount, instanceCount,
1010 gl::DrawElementsType::InvalidEnum, nullptr, dirtyBitMask));
1011
1012 // Process indirect buffer after render pass has started.
1013 mRenderPassCommands->bufferRead(this, VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
1014 vk::PipelineStage::DrawIndirect, indirectBuffer);
1015
1016 return angle::Result::Continue;
1017 }
1018
setupIndexedIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType indexType,vk::BufferHelper * indirectBuffer,VkDeviceSize indirectBufferOffset)1019 angle::Result ContextVk::setupIndexedIndirectDraw(const gl::Context *context,
1020 gl::PrimitiveMode mode,
1021 gl::DrawElementsType indexType,
1022 vk::BufferHelper *indirectBuffer,
1023 VkDeviceSize indirectBufferOffset)
1024 {
1025 ASSERT(mode != gl::PrimitiveMode::LineLoop);
1026
1027 if (indexType != mCurrentDrawElementsType)
1028 {
1029 mCurrentDrawElementsType = indexType;
1030 ANGLE_TRY(onIndexBufferChange(nullptr));
1031 }
1032
1033 return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, indirectBuffer,
1034 indirectBufferOffset);
1035 }
1036
setupLineLoopIndexedIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType indexType,vk::BufferHelper * srcIndirectBuf,VkDeviceSize indirectBufferOffset,vk::BufferHelper ** indirectBufferOut,VkDeviceSize * indirectBufferOffsetOut)1037 angle::Result ContextVk::setupLineLoopIndexedIndirectDraw(const gl::Context *context,
1038 gl::PrimitiveMode mode,
1039 gl::DrawElementsType indexType,
1040 vk::BufferHelper *srcIndirectBuf,
1041 VkDeviceSize indirectBufferOffset,
1042 vk::BufferHelper **indirectBufferOut,
1043 VkDeviceSize *indirectBufferOffsetOut)
1044 {
1045 ASSERT(mode == gl::PrimitiveMode::LineLoop);
1046
1047 vk::BufferHelper *dstIndirectBuf = nullptr;
1048 VkDeviceSize dstIndirectBufOffset = 0;
1049
1050 ANGLE_TRY(mVertexArray->handleLineLoopIndexIndirect(this, indexType, srcIndirectBuf,
1051 indirectBufferOffset, &dstIndirectBuf,
1052 &dstIndirectBufOffset));
1053
1054 *indirectBufferOut = dstIndirectBuf;
1055 *indirectBufferOffsetOut = dstIndirectBufOffset;
1056
1057 if (indexType != mCurrentDrawElementsType)
1058 {
1059 mCurrentDrawElementsType = indexType;
1060 ANGLE_TRY(onIndexBufferChange(nullptr));
1061 }
1062
1063 return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, dstIndirectBuf,
1064 dstIndirectBufOffset);
1065 }
1066
setupLineLoopIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,vk::BufferHelper * indirectBuffer,VkDeviceSize indirectBufferOffset,vk::BufferHelper ** indirectBufferOut,VkDeviceSize * indirectBufferOffsetOut)1067 angle::Result ContextVk::setupLineLoopIndirectDraw(const gl::Context *context,
1068 gl::PrimitiveMode mode,
1069 vk::BufferHelper *indirectBuffer,
1070 VkDeviceSize indirectBufferOffset,
1071 vk::BufferHelper **indirectBufferOut,
1072 VkDeviceSize *indirectBufferOffsetOut)
1073 {
1074 ASSERT(mode == gl::PrimitiveMode::LineLoop);
1075
1076 vk::BufferHelper *indirectBufferHelperOut = nullptr;
1077
1078 ANGLE_TRY(mVertexArray->handleLineLoopIndirectDraw(
1079 context, indirectBuffer, indirectBufferOffset, &indirectBufferHelperOut,
1080 indirectBufferOffsetOut));
1081
1082 *indirectBufferOut = indirectBufferHelperOut;
1083
1084 if (gl::DrawElementsType::UnsignedInt != mCurrentDrawElementsType)
1085 {
1086 mCurrentDrawElementsType = gl::DrawElementsType::UnsignedInt;
1087 ANGLE_TRY(onIndexBufferChange(nullptr));
1088 }
1089
1090 return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, indirectBufferHelperOut,
1091 *indirectBufferOffsetOut);
1092 }
1093
setupLineLoopDraw(const gl::Context * context,gl::PrimitiveMode mode,GLint firstVertex,GLsizei vertexOrIndexCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,uint32_t * numIndicesOut)1094 angle::Result ContextVk::setupLineLoopDraw(const gl::Context *context,
1095 gl::PrimitiveMode mode,
1096 GLint firstVertex,
1097 GLsizei vertexOrIndexCount,
1098 gl::DrawElementsType indexTypeOrInvalid,
1099 const void *indices,
1100 uint32_t *numIndicesOut)
1101 {
1102 mCurrentIndexBufferOffset = 0;
1103 ANGLE_TRY(mVertexArray->handleLineLoop(this, firstVertex, vertexOrIndexCount,
1104 indexTypeOrInvalid, indices, numIndicesOut));
1105 ANGLE_TRY(onIndexBufferChange(nullptr));
1106 mCurrentDrawElementsType = indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum
1107 ? indexTypeOrInvalid
1108 : gl::DrawElementsType::UnsignedInt;
1109 return setupDraw(context, mode, firstVertex, vertexOrIndexCount, 1, indexTypeOrInvalid, indices,
1110 mIndexedDirtyBitsMask);
1111 }
1112
setupDispatch(const gl::Context * context)1113 angle::Result ContextVk::setupDispatch(const gl::Context *context)
1114 {
1115 // Note: numerous tests miss a glMemoryBarrier call between the initial texture data upload and
1116 // the dispatch call. Flush the outside render pass command buffer as a workaround.
1117 // TODO: Remove this and fix tests. http://anglebug.com/5070
1118 ANGLE_TRY(flushOutsideRenderPassCommands());
1119
1120 // Create a local object to ensure we flush the descriptor updates to device when we leave this
1121 // function
1122 ScopedDescriptorSetUpdates descriptorSetUpdates(this);
1123
1124 if (mProgram && mProgram->dirtyUniforms())
1125 {
1126 ANGLE_TRY(mProgram->updateUniforms(this));
1127 mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
1128 }
1129 else if (mProgramPipeline && mProgramPipeline->dirtyUniforms(getState()))
1130 {
1131 ANGLE_TRY(mProgramPipeline->updateUniforms(this));
1132 mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
1133 }
1134
1135 DirtyBits dirtyBits = mComputeDirtyBits;
1136
1137 // Flush any relevant dirty bits.
1138 for (size_t dirtyBit : dirtyBits)
1139 {
1140 ASSERT(mComputeDirtyBitHandlers[dirtyBit]);
1141 ANGLE_TRY((this->*mComputeDirtyBitHandlers[dirtyBit])());
1142 }
1143
1144 mComputeDirtyBits.reset();
1145
1146 return angle::Result::Continue;
1147 }
1148
handleDirtyGraphicsMemoryBarrier(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1149 angle::Result ContextVk::handleDirtyGraphicsMemoryBarrier(DirtyBits::Iterator *dirtyBitsIterator,
1150 DirtyBits dirtyBitMask)
1151 {
1152 return handleDirtyMemoryBarrierImpl(dirtyBitsIterator, dirtyBitMask);
1153 }
1154
handleDirtyComputeMemoryBarrier()1155 angle::Result ContextVk::handleDirtyComputeMemoryBarrier()
1156 {
1157 return handleDirtyMemoryBarrierImpl(nullptr, {});
1158 }
1159
renderPassUsesStorageResources() const1160 bool ContextVk::renderPassUsesStorageResources() const
1161 {
1162 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1163 ASSERT(executable);
1164
1165 // Storage images:
1166 for (size_t imageUnitIndex : executable->getActiveImagesMask())
1167 {
1168 const gl::Texture *texture = mState.getImageUnit(imageUnitIndex).texture.get();
1169 if (texture == nullptr)
1170 {
1171 continue;
1172 }
1173
1174 TextureVk *textureVk = vk::GetImpl(texture);
1175
1176 if (texture->getType() == gl::TextureType::Buffer)
1177 {
1178 VkDeviceSize bufferOffset = 0;
1179 vk::BufferHelper &buffer =
1180 vk::GetImpl(textureVk->getBuffer().get())->getBufferAndOffset(&bufferOffset);
1181 if (mRenderPassCommands->usesBuffer(buffer))
1182 {
1183 return true;
1184 }
1185 }
1186 else
1187 {
1188 vk::ImageHelper &image = textureVk->getImage();
1189 // Images only need to close the render pass if they need a layout transition. Outside
1190 // render pass command buffer doesn't need closing as the layout transition barriers are
1191 // recorded in sequence with the rest of the commands.
1192 if (IsRenderPassStartedAndUsesImage(*mRenderPassCommands, image))
1193 {
1194 return true;
1195 }
1196 }
1197 }
1198
1199 gl::ShaderMap<const gl::ProgramState *> programStates;
1200 mExecutable->fillProgramStateMap(this, &programStates);
1201
1202 for (const gl::ShaderType shaderType : executable->getLinkedShaderStages())
1203 {
1204 const gl::ProgramState *programState = programStates[shaderType];
1205 ASSERT(programState);
1206
1207 // Storage buffers:
1208 const std::vector<gl::InterfaceBlock> &blocks = programState->getShaderStorageBlocks();
1209
1210 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
1211 {
1212 const gl::InterfaceBlock &block = blocks[bufferIndex];
1213 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1214 mState.getIndexedShaderStorageBuffer(block.binding);
1215
1216 if (!block.isActive(shaderType) || bufferBinding.get() == nullptr)
1217 {
1218 continue;
1219 }
1220
1221 VkDeviceSize bufferOffset = 0;
1222 vk::BufferHelper &buffer =
1223 vk::GetImpl(bufferBinding.get())->getBufferAndOffset(&bufferOffset);
1224 if (mRenderPassCommands->usesBuffer(buffer))
1225 {
1226 return true;
1227 }
1228 }
1229
1230 // Atomic counters:
1231 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers =
1232 programState->getAtomicCounterBuffers();
1233
1234 for (uint32_t bufferIndex = 0; bufferIndex < atomicCounterBuffers.size(); ++bufferIndex)
1235 {
1236 uint32_t binding = atomicCounterBuffers[bufferIndex].binding;
1237 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1238 mState.getIndexedAtomicCounterBuffer(binding);
1239
1240 if (bufferBinding.get() == nullptr)
1241 {
1242 continue;
1243 }
1244
1245 VkDeviceSize bufferOffset = 0;
1246 vk::BufferHelper &buffer =
1247 vk::GetImpl(bufferBinding.get())->getBufferAndOffset(&bufferOffset);
1248 if (mRenderPassCommands->usesBuffer(buffer))
1249 {
1250 return true;
1251 }
1252 }
1253 }
1254
1255 return false;
1256 }
1257
handleDirtyMemoryBarrierImpl(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1258 angle::Result ContextVk::handleDirtyMemoryBarrierImpl(DirtyBits::Iterator *dirtyBitsIterator,
1259 DirtyBits dirtyBitMask)
1260 {
1261 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1262 ASSERT(executable);
1263
1264 const bool hasImages = executable->hasImages();
1265 const bool hasStorageBuffers = executable->hasStorageBuffers();
1266 const bool hasAtomicCounters = executable->hasAtomicCounterBuffers();
1267
1268 if (!hasImages && !hasStorageBuffers && !hasAtomicCounters)
1269 {
1270 return angle::Result::Continue;
1271 }
1272
1273 // Break the render pass if necessary. This is only needed for write-after-read situations, and
1274 // is done by checking whether current storage buffers and images are used in the render pass.
1275 if (renderPassUsesStorageResources())
1276 {
1277 // Either set later bits (if called during handling of graphics dirty bits), or set the
1278 // dirty bits directly (if called during handling of compute dirty bits).
1279 if (dirtyBitsIterator)
1280 {
1281 return flushDirtyGraphicsRenderPass(dirtyBitsIterator, dirtyBitMask);
1282 }
1283 else
1284 {
1285 return flushCommandsAndEndRenderPass();
1286 }
1287 }
1288
1289 // Flushing outside render pass commands is cheap. If a memory barrier has been issued in its
1290 // life time, just flush it instead of wasting time trying to figure out if it's necessary.
1291 if (mOutsideRenderPassCommands->hasGLMemoryBarrierIssued())
1292 {
1293 ANGLE_TRY(flushOutsideRenderPassCommands());
1294 }
1295
1296 return angle::Result::Continue;
1297 }
1298
handleDirtyGraphicsEventLog(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1299 angle::Result ContextVk::handleDirtyGraphicsEventLog(DirtyBits::Iterator *dirtyBitsIterator,
1300 DirtyBits dirtyBitMask)
1301 {
1302 return handleDirtyEventLogImpl(mRenderPassCommandBuffer);
1303 }
1304
handleDirtyComputeEventLog()1305 angle::Result ContextVk::handleDirtyComputeEventLog()
1306 {
1307 return handleDirtyEventLogImpl(&mOutsideRenderPassCommands->getCommandBuffer());
1308 }
1309
handleDirtyEventLogImpl(vk::CommandBuffer * commandBuffer)1310 angle::Result ContextVk::handleDirtyEventLogImpl(vk::CommandBuffer *commandBuffer)
1311 {
1312 // This method is called when a draw or dispatch command is being processed. It's purpose is
1313 // to call the vkCmd*DebugUtilsLabelEXT functions in order to communicate to debuggers
1314 // (e.g. AGI) the OpenGL ES commands that the application uses.
1315
1316 // Exit early if no OpenGL ES commands have been logged, or if no command buffer (for a no-op
1317 // draw), or if calling the vkCmd*DebugUtilsLabelEXT functions is not enabled.
1318 if (mEventLog.empty() || commandBuffer == nullptr || !mRenderer->angleDebuggerMode())
1319 {
1320 return angle::Result::Continue;
1321 }
1322
1323 // Insert OpenGL ES commands into debug label. We create a 3-level cascade here for
1324 // OpenGL-ES-first debugging in AGI. Here's the general outline of commands:
1325 // -glDrawCommand
1326 // --vkCmdBeginDebugUtilsLabelEXT() #1 for "glDrawCommand"
1327 // --OpenGL ES Commands
1328 // ---vkCmdBeginDebugUtilsLabelEXT() #2 for "OpenGL ES Commands"
1329 // ---Individual OpenGL ES Commands leading up to glDrawCommand
1330 // ----vkCmdBeginDebugUtilsLabelEXT() #3 for each individual OpenGL ES Command
1331 // ----vkCmdEndDebugUtilsLabelEXT() #3 for each individual OpenGL ES Command
1332 // ----...More Individual OGL Commands...
1333 // ----Final Individual OGL command will be the same glDrawCommand shown in #1 above
1334 // ---vkCmdEndDebugUtilsLabelEXT() #2 for "OpenGL ES Commands"
1335 // --VK SetupDraw & Draw-related commands will be embedded here under glDraw #1
1336 // --vkCmdEndDebugUtilsLabelEXT() #1 is called after each vkDraw* or vkDispatch* call
1337 VkDebugUtilsLabelEXT label = {VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
1338 nullptr,
1339 mEventLog.back().c_str(),
1340 {0.0f, 0.0f, 0.0f, 0.0f}};
1341 // This is #1 from comment above
1342 commandBuffer->beginDebugUtilsLabelEXT(label);
1343 std::string oglCmds = "OpenGL ES Commands";
1344 label.pLabelName = oglCmds.c_str();
1345 // This is #2 from comment above
1346 commandBuffer->beginDebugUtilsLabelEXT(label);
1347 for (uint32_t i = 0; i < mEventLog.size(); ++i)
1348 {
1349 label.pLabelName = mEventLog[i].c_str();
1350 // NOTE: We have to use a begin/end pair here because AGI does not promote the
1351 // pLabelName from an insertDebugUtilsLabelEXT() call to the Commands panel.
1352 // Internal bug b/169243237 is tracking this and once the insert* call shows the
1353 // pLabelName similar to begin* call, we can switch these to insert* calls instead.
1354 // This is #3 from comment above.
1355 commandBuffer->beginDebugUtilsLabelEXT(label);
1356 commandBuffer->endDebugUtilsLabelEXT();
1357 }
1358 commandBuffer->endDebugUtilsLabelEXT();
1359 // The final end* call for #1 above is made in the ContextVk::draw* or
1360 // ContextVk::dispatch* function calls.
1361
1362 mEventLog.clear();
1363 return angle::Result::Continue;
1364 }
1365
handleDirtyGraphicsDefaultAttribs(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1366 angle::Result ContextVk::handleDirtyGraphicsDefaultAttribs(DirtyBits::Iterator *dirtyBitsIterator,
1367 DirtyBits dirtyBitMask)
1368 {
1369 ASSERT(mDirtyDefaultAttribsMask.any());
1370
1371 for (size_t attribIndex : mDirtyDefaultAttribsMask)
1372 {
1373 ANGLE_TRY(updateDefaultAttribute(attribIndex));
1374 }
1375
1376 mDirtyDefaultAttribsMask.reset();
1377 return angle::Result::Continue;
1378 }
1379
handleDirtyGraphicsPipelineDesc(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1380 angle::Result ContextVk::handleDirtyGraphicsPipelineDesc(DirtyBits::Iterator *dirtyBitsIterator,
1381 DirtyBits dirtyBitMask)
1382 {
1383 const VkPipeline previousPipeline = mCurrentGraphicsPipeline
1384 ? mCurrentGraphicsPipeline->getPipeline().getHandle()
1385 : VK_NULL_HANDLE;
1386
1387 ASSERT(mExecutable);
1388
1389 if (!mCurrentGraphicsPipeline)
1390 {
1391 const vk::GraphicsPipelineDesc *descPtr;
1392
1393 // The desc's specialization constant depends on program's
1394 // specConstUsageBits. We need to update it if program has changed.
1395 SpecConstUsageBits usageBits = getCurrentProgramSpecConstUsageBits();
1396 updateGraphicsPipelineDescWithSpecConstUsageBits(usageBits);
1397
1398 // Draw call shader patching, shader compilation, and pipeline cache query.
1399 ANGLE_TRY(mExecutable->getGraphicsPipeline(
1400 this, mCurrentDrawMode, *mGraphicsPipelineDesc,
1401 mState.getProgramExecutable()->getNonBuiltinAttribLocationsMask(), &descPtr,
1402 &mCurrentGraphicsPipeline));
1403 mGraphicsPipelineTransition.reset();
1404 }
1405 else if (mGraphicsPipelineTransition.any())
1406 {
1407 ASSERT(mCurrentGraphicsPipeline->valid());
1408 if (!mCurrentGraphicsPipeline->findTransition(
1409 mGraphicsPipelineTransition, *mGraphicsPipelineDesc, &mCurrentGraphicsPipeline))
1410 {
1411 vk::PipelineHelper *oldPipeline = mCurrentGraphicsPipeline;
1412 const vk::GraphicsPipelineDesc *descPtr;
1413
1414 ANGLE_TRY(mExecutable->getGraphicsPipeline(
1415 this, mCurrentDrawMode, *mGraphicsPipelineDesc,
1416 mState.getProgramExecutable()->getNonBuiltinAttribLocationsMask(), &descPtr,
1417 &mCurrentGraphicsPipeline));
1418
1419 oldPipeline->addTransition(mGraphicsPipelineTransition, descPtr,
1420 mCurrentGraphicsPipeline);
1421 }
1422
1423 mGraphicsPipelineTransition.reset();
1424 }
1425 // Update the queue serial for the pipeline object.
1426 ASSERT(mCurrentGraphicsPipeline && mCurrentGraphicsPipeline->valid());
1427 // TODO: https://issuetracker.google.com/issues/169788986: Need to change this so that we get
1428 // the actual serial used when this work is submitted.
1429 mCurrentGraphicsPipeline->updateSerial(getCurrentQueueSerial());
1430
1431 const VkPipeline newPipeline = mCurrentGraphicsPipeline->getPipeline().getHandle();
1432
1433 // If there's no change in pipeline, avoid rebinding it later. If the rebind is due to a new
1434 // command buffer or UtilsVk, it will happen anyway with DIRTY_BIT_PIPELINE_BINDING.
1435 if (newPipeline == previousPipeline)
1436 {
1437 return angle::Result::Continue;
1438 }
1439
1440 // VK_EXT_transform_feedback disallows binding pipelines while transform feedback is active.
1441 // If a new pipeline needs to be bound, the render pass should necessarily be broken (which
1442 // implicitly pauses transform feedback), as resuming requires a barrier on the transform
1443 // feedback counter buffer.
1444 if (mRenderPassCommands->started() && mRenderPassCommands->isTransformFeedbackActiveUnpaused())
1445 {
1446 ANGLE_TRY(flushDirtyGraphicsRenderPass(dirtyBitsIterator, dirtyBitMask));
1447
1448 dirtyBitsIterator->setLaterBit(DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME);
1449 }
1450
1451 // The pipeline needs to rebind because it's changed.
1452 dirtyBitsIterator->setLaterBit(DIRTY_BIT_PIPELINE_BINDING);
1453
1454 return angle::Result::Continue;
1455 }
1456
handleDirtyGraphicsRenderPass(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1457 angle::Result ContextVk::handleDirtyGraphicsRenderPass(DirtyBits::Iterator *dirtyBitsIterator,
1458 DirtyBits dirtyBitMask)
1459 {
1460 // If the render pass needs to be recreated, close it using the special mid-dirty-bit-handling
1461 // function, so later dirty bits can be set.
1462 if (mRenderPassCommands->started())
1463 {
1464 ANGLE_TRY(flushDirtyGraphicsRenderPass(dirtyBitsIterator,
1465 dirtyBitMask & ~DirtyBits{DIRTY_BIT_RENDER_PASS}));
1466 }
1467
1468 gl::Rectangle scissoredRenderArea = mDrawFramebuffer->getRotatedScissoredRenderArea(this);
1469 bool renderPassDescChanged = false;
1470
1471 ANGLE_TRY(startRenderPass(scissoredRenderArea, nullptr, &renderPassDescChanged));
1472
1473 // The render pass desc can change when starting the render pass, for example due to
1474 // multisampled-render-to-texture needs based on loadOps. In that case, recreate the graphics
1475 // pipeline.
1476 if (renderPassDescChanged)
1477 {
1478 ANGLE_TRY(handleDirtyGraphicsPipelineDesc(dirtyBitsIterator, dirtyBitMask));
1479 }
1480
1481 return angle::Result::Continue;
1482 }
1483
handleDirtyGraphicsPipelineBinding(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1484 angle::Result ContextVk::handleDirtyGraphicsPipelineBinding(DirtyBits::Iterator *dirtyBitsIterator,
1485 DirtyBits dirtyBitMask)
1486 {
1487 ASSERT(mCurrentGraphicsPipeline);
1488
1489 mRenderPassCommandBuffer->bindGraphicsPipeline(mCurrentGraphicsPipeline->getPipeline());
1490
1491 return angle::Result::Continue;
1492 }
1493
handleDirtyComputePipelineDesc()1494 angle::Result ContextVk::handleDirtyComputePipelineDesc()
1495 {
1496 if (!mCurrentComputePipeline)
1497 {
1498 ASSERT(mExecutable);
1499 ANGLE_TRY(mExecutable->getComputePipeline(this, &mCurrentComputePipeline));
1500 }
1501
1502 ASSERT(mComputeDirtyBits.test(DIRTY_BIT_PIPELINE_BINDING));
1503
1504 return angle::Result::Continue;
1505 }
1506
handleDirtyComputePipelineBinding()1507 angle::Result ContextVk::handleDirtyComputePipelineBinding()
1508 {
1509 ASSERT(mCurrentComputePipeline);
1510
1511 mOutsideRenderPassCommands->getCommandBuffer().bindComputePipeline(
1512 mCurrentComputePipeline->get());
1513 // TODO: https://issuetracker.google.com/issues/169788986: Need to change this so that we get
1514 // the actual serial used when this work is submitted.
1515 mCurrentComputePipeline->updateSerial(getCurrentQueueSerial());
1516
1517 return angle::Result::Continue;
1518 }
1519
handleDirtyTexturesImpl(vk::CommandBufferHelper * commandBufferHelper)1520 ANGLE_INLINE angle::Result ContextVk::handleDirtyTexturesImpl(
1521 vk::CommandBufferHelper *commandBufferHelper)
1522 {
1523 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1524 ASSERT(executable);
1525 const gl::ActiveTextureMask &activeTextures = executable->getActiveSamplersMask();
1526
1527 for (size_t textureUnit : activeTextures)
1528 {
1529 const vk::TextureUnit &unit = mActiveTextures[textureUnit];
1530 TextureVk *textureVk = unit.texture;
1531
1532 // If it's a texture buffer, get the attached buffer.
1533 if (textureVk->getBuffer().get() != nullptr)
1534 {
1535 BufferVk *bufferVk = vk::GetImpl(textureVk->getBuffer().get());
1536 VkDeviceSize bufferOffset = 0;
1537 vk::BufferHelper &buffer = bufferVk->getBufferAndOffset(&bufferOffset);
1538
1539 gl::ShaderBitSet stages =
1540 executable->getSamplerShaderBitsForTextureUnitIndex(textureUnit);
1541 ASSERT(stages.any());
1542
1543 // TODO: accept multiple stages in bufferRead. http://anglebug.com/3573
1544 for (gl::ShaderType stage : stages)
1545 {
1546 // Note: if another range of the same buffer is simultaneously used for storage,
1547 // such as for transform feedback output, or SSBO, unnecessary barriers can be
1548 // generated.
1549 commandBufferHelper->bufferRead(this, VK_ACCESS_SHADER_READ_BIT,
1550 vk::GetPipelineStage(stage), &buffer);
1551 }
1552
1553 textureVk->retainBufferViews(&mResourceUseList);
1554
1555 continue;
1556 }
1557
1558 vk::ImageHelper &image = textureVk->getImage();
1559
1560 // The image should be flushed and ready to use at this point. There may still be
1561 // lingering staged updates in its staging buffer for unused texture mip levels or
1562 // layers. Therefore we can't verify it has no staged updates right here.
1563
1564 // Select the appropriate vk::ImageLayout depending on whether the texture is also bound as
1565 // a GL image, and whether the program is a compute or graphics shader.
1566 vk::ImageLayout textureLayout;
1567 if (textureVk->hasBeenBoundAsImage())
1568 {
1569 textureLayout = executable->isCompute() ? vk::ImageLayout::ComputeShaderWrite
1570 : vk::ImageLayout::AllGraphicsShadersWrite;
1571 }
1572 else
1573 {
1574 gl::ShaderBitSet remainingShaderBits =
1575 executable->getSamplerShaderBitsForTextureUnitIndex(textureUnit);
1576 ASSERT(remainingShaderBits.any());
1577 gl::ShaderType firstShader = remainingShaderBits.first();
1578 gl::ShaderType lastShader = remainingShaderBits.last();
1579 remainingShaderBits.reset(firstShader);
1580 remainingShaderBits.reset(lastShader);
1581
1582 if (image.hasRenderPassUsageFlag(vk::RenderPassUsage::RenderTargetAttachment))
1583 {
1584 // Right now we set this flag only when RenderTargetAttachment is set since we do
1585 // not track all textures in the renderpass.
1586 image.setRenderPassUsageFlag(vk::RenderPassUsage::TextureSampler);
1587
1588 if (image.isDepthOrStencil())
1589 {
1590 if (image.hasRenderPassUsageFlag(vk::RenderPassUsage::ReadOnlyAttachment))
1591 {
1592 if (firstShader == gl::ShaderType::Fragment)
1593 {
1594 ASSERT(remainingShaderBits.none() && lastShader == firstShader);
1595 textureLayout = vk::ImageLayout::DSAttachmentReadAndFragmentShaderRead;
1596 }
1597 else
1598 {
1599 textureLayout = vk::ImageLayout::DSAttachmentReadAndAllShadersRead;
1600 }
1601 }
1602 else
1603 {
1604 if (firstShader == gl::ShaderType::Fragment)
1605 {
1606 textureLayout = vk::ImageLayout::DSAttachmentWriteAndFragmentShaderRead;
1607 }
1608 else
1609 {
1610 textureLayout = vk::ImageLayout::DSAttachmentWriteAndAllShadersRead;
1611 }
1612 }
1613 }
1614 else
1615 {
1616 if (firstShader == gl::ShaderType::Fragment)
1617 {
1618 textureLayout = vk::ImageLayout::ColorAttachmentAndFragmentShaderRead;
1619 }
1620 else
1621 {
1622 textureLayout = vk::ImageLayout::ColorAttachmentAndAllShadersRead;
1623 }
1624 }
1625 }
1626 else if (image.isDepthOrStencil())
1627 {
1628 // We always use a depth-stencil read-only layout for any depth Textures to simplify
1629 // our implementation's handling of depth-stencil read-only mode. We don't have to
1630 // split a RenderPass to transition a depth texture from shader-read to read-only.
1631 // This improves performance in Manhattan. Future optimizations are likely possible
1632 // here including using specialized barriers without breaking the RenderPass.
1633 if (firstShader == gl::ShaderType::Fragment)
1634 {
1635 ASSERT(remainingShaderBits.none() && lastShader == firstShader);
1636 textureLayout = vk::ImageLayout::DSAttachmentReadAndFragmentShaderRead;
1637 }
1638 else
1639 {
1640 textureLayout = vk::ImageLayout::DSAttachmentReadAndAllShadersRead;
1641 }
1642 }
1643 else
1644 {
1645 // We barrier against either:
1646 // - Vertex only
1647 // - Fragment only
1648 // - Pre-fragment only (vertex, geometry and tessellation together)
1649 if (remainingShaderBits.any() || firstShader != lastShader)
1650 {
1651 textureLayout = lastShader == gl::ShaderType::Fragment
1652 ? vk::ImageLayout::AllGraphicsShadersReadOnly
1653 : vk::ImageLayout::PreFragmentShadersReadOnly;
1654 }
1655 else
1656 {
1657 textureLayout = kShaderReadOnlyImageLayouts[firstShader];
1658 }
1659 }
1660 }
1661 // Ensure the image is in the desired layout
1662 commandBufferHelper->imageRead(this, image.getAspectFlags(), textureLayout, &image);
1663
1664 textureVk->retainImageViews(&mResourceUseList);
1665 }
1666
1667 if (executable->hasTextures())
1668 {
1669 ANGLE_TRY(mExecutable->updateTexturesDescriptorSet(this, mActiveTexturesDesc));
1670 }
1671
1672 return angle::Result::Continue;
1673 }
1674
handleDirtyGraphicsTextures(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1675 angle::Result ContextVk::handleDirtyGraphicsTextures(DirtyBits::Iterator *dirtyBitsIterator,
1676 DirtyBits dirtyBitMask)
1677 {
1678 return handleDirtyTexturesImpl(mRenderPassCommands);
1679 }
1680
handleDirtyComputeTextures()1681 angle::Result ContextVk::handleDirtyComputeTextures()
1682 {
1683 return handleDirtyTexturesImpl(mOutsideRenderPassCommands);
1684 }
1685
handleDirtyGraphicsVertexBuffers(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1686 angle::Result ContextVk::handleDirtyGraphicsVertexBuffers(DirtyBits::Iterator *dirtyBitsIterator,
1687 DirtyBits dirtyBitMask)
1688 {
1689 uint32_t maxAttrib = mState.getProgramExecutable()->getMaxActiveAttribLocation();
1690 const gl::AttribArray<VkBuffer> &bufferHandles = mVertexArray->getCurrentArrayBufferHandles();
1691 const gl::AttribArray<VkDeviceSize> &bufferOffsets =
1692 mVertexArray->getCurrentArrayBufferOffsets();
1693
1694 mRenderPassCommandBuffer->bindVertexBuffers(0, maxAttrib, bufferHandles.data(),
1695 bufferOffsets.data());
1696
1697 const gl::AttribArray<vk::BufferHelper *> &arrayBufferResources =
1698 mVertexArray->getCurrentArrayBuffers();
1699
1700 // Mark all active vertex buffers as accessed.
1701 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1702 gl::AttributesMask attribsMask = executable->getActiveAttribLocationsMask();
1703 for (size_t attribIndex : attribsMask)
1704 {
1705 vk::BufferHelper *arrayBuffer = arrayBufferResources[attribIndex];
1706 if (arrayBuffer)
1707 {
1708 mRenderPassCommands->bufferRead(this, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
1709 vk::PipelineStage::VertexInput, arrayBuffer);
1710 }
1711 }
1712
1713 return angle::Result::Continue;
1714 }
1715
handleDirtyGraphicsIndexBuffer(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1716 angle::Result ContextVk::handleDirtyGraphicsIndexBuffer(DirtyBits::Iterator *dirtyBitsIterator,
1717 DirtyBits dirtyBitMask)
1718 {
1719 vk::BufferHelper *elementArrayBuffer = mVertexArray->getCurrentElementArrayBuffer();
1720 ASSERT(elementArrayBuffer != nullptr);
1721
1722 VkDeviceSize offset =
1723 mVertexArray->getCurrentElementArrayBufferOffset() + mCurrentIndexBufferOffset;
1724
1725 mRenderPassCommandBuffer->bindIndexBuffer(elementArrayBuffer->getBuffer(), offset,
1726 getVkIndexType(mCurrentDrawElementsType));
1727
1728 mRenderPassCommands->bufferRead(this, VK_ACCESS_INDEX_READ_BIT, vk::PipelineStage::VertexInput,
1729 elementArrayBuffer);
1730
1731 return angle::Result::Continue;
1732 }
1733
handleDirtyGraphicsFramebufferFetchBarrier(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1734 angle::Result ContextVk::handleDirtyGraphicsFramebufferFetchBarrier(
1735 DirtyBits::Iterator *dirtyBitsIterator,
1736 DirtyBits dirtyBitMask)
1737 {
1738 VkMemoryBarrier memoryBarrier = {};
1739 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
1740 memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1741 memoryBarrier.dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
1742
1743 mRenderPassCommandBuffer->pipelineBarrier(
1744 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
1745 VK_DEPENDENCY_BY_REGION_BIT, 1, &memoryBarrier, 0, nullptr, 0, nullptr);
1746
1747 return angle::Result::Continue;
1748 }
1749
handleDirtyShaderResourcesImpl(vk::CommandBufferHelper * commandBufferHelper)1750 ANGLE_INLINE angle::Result ContextVk::handleDirtyShaderResourcesImpl(
1751 vk::CommandBufferHelper *commandBufferHelper)
1752 {
1753 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1754 ASSERT(executable);
1755
1756 const bool hasImages = executable->hasImages();
1757 const bool hasStorageBuffers =
1758 executable->hasStorageBuffers() || executable->hasAtomicCounterBuffers();
1759 const bool hasUniformBuffers = executable->hasUniformBuffers();
1760
1761 if (!hasUniformBuffers && !hasStorageBuffers && !hasImages &&
1762 !executable->usesFramebufferFetch())
1763 {
1764 return angle::Result::Continue;
1765 }
1766
1767 if (hasImages)
1768 {
1769 ANGLE_TRY(updateActiveImages(commandBufferHelper));
1770 }
1771
1772 // Process buffer barriers.
1773 gl::ShaderMap<const gl::ProgramState *> programStates;
1774 mExecutable->fillProgramStateMap(this, &programStates);
1775 for (const gl::ShaderType shaderType : executable->getLinkedShaderStages())
1776 {
1777 const gl::ProgramState &programState = *programStates[shaderType];
1778 const std::vector<gl::InterfaceBlock> &ubos = programState.getUniformBlocks();
1779
1780 for (const gl::InterfaceBlock &ubo : ubos)
1781 {
1782 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1783 mState.getIndexedUniformBuffer(ubo.binding);
1784
1785 if (!ubo.isActive(shaderType))
1786 {
1787 continue;
1788 }
1789
1790 if (bufferBinding.get() == nullptr)
1791 {
1792 continue;
1793 }
1794
1795 BufferVk *bufferVk = vk::GetImpl(bufferBinding.get());
1796 VkDeviceSize bufferOffset = 0;
1797 vk::BufferHelper &bufferHelper = bufferVk->getBufferAndOffset(&bufferOffset);
1798
1799 commandBufferHelper->bufferRead(this, VK_ACCESS_UNIFORM_READ_BIT,
1800 vk::GetPipelineStage(shaderType), &bufferHelper);
1801 }
1802
1803 const std::vector<gl::InterfaceBlock> &ssbos = programState.getShaderStorageBlocks();
1804 for (const gl::InterfaceBlock &ssbo : ssbos)
1805 {
1806 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1807 mState.getIndexedShaderStorageBuffer(ssbo.binding);
1808
1809 if (!ssbo.isActive(shaderType))
1810 {
1811 continue;
1812 }
1813
1814 if (bufferBinding.get() == nullptr)
1815 {
1816 continue;
1817 }
1818
1819 BufferVk *bufferVk = vk::GetImpl(bufferBinding.get());
1820 VkDeviceSize bufferOffset = 0;
1821 vk::BufferHelper &bufferHelper = bufferVk->getBufferAndOffset(&bufferOffset);
1822
1823 // We set the SHADER_READ_BIT to be conservative.
1824 VkAccessFlags accessFlags = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
1825 commandBufferHelper->bufferWrite(this, accessFlags, vk::GetPipelineStage(shaderType),
1826 vk::AliasingMode::Allowed, &bufferHelper);
1827 }
1828
1829 const std::vector<gl::AtomicCounterBuffer> &acbs = programState.getAtomicCounterBuffers();
1830 for (const gl::AtomicCounterBuffer &atomicCounterBuffer : acbs)
1831 {
1832 uint32_t binding = atomicCounterBuffer.binding;
1833 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1834 mState.getIndexedAtomicCounterBuffer(binding);
1835
1836 if (bufferBinding.get() == nullptr)
1837 {
1838 continue;
1839 }
1840
1841 BufferVk *bufferVk = vk::GetImpl(bufferBinding.get());
1842 VkDeviceSize bufferOffset = 0;
1843 vk::BufferHelper &bufferHelper = bufferVk->getBufferAndOffset(&bufferOffset);
1844
1845 // We set SHADER_READ_BIT to be conservative.
1846 commandBufferHelper->bufferWrite(
1847 this, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
1848 vk::GetPipelineStage(shaderType), vk::AliasingMode::Allowed, &bufferHelper);
1849 }
1850 }
1851
1852 ANGLE_TRY(mExecutable->updateShaderResourcesDescriptorSet(
1853 this, mDrawFramebuffer, mShaderBuffersDescriptorDesc, commandBufferHelper));
1854
1855 // Record usage of storage buffers and images in the command buffer to aid handling of
1856 // glMemoryBarrier.
1857 if (hasImages || hasStorageBuffers)
1858 {
1859 commandBufferHelper->setHasShaderStorageOutput();
1860 }
1861
1862 return angle::Result::Continue;
1863 }
1864
handleDirtyGraphicsShaderResources(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1865 angle::Result ContextVk::handleDirtyGraphicsShaderResources(DirtyBits::Iterator *dirtyBitsIterator,
1866 DirtyBits dirtyBitMask)
1867 {
1868 return handleDirtyShaderResourcesImpl(mRenderPassCommands);
1869 }
1870
handleDirtyComputeShaderResources()1871 angle::Result ContextVk::handleDirtyComputeShaderResources()
1872 {
1873 return handleDirtyShaderResourcesImpl(mOutsideRenderPassCommands);
1874 }
1875
handleDirtyGraphicsTransformFeedbackBuffersEmulation(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1876 angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffersEmulation(
1877 DirtyBits::Iterator *dirtyBitsIterator,
1878 DirtyBits dirtyBitMask)
1879 {
1880 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1881 ASSERT(executable);
1882
1883 if (!executable->hasTransformFeedbackOutput())
1884 {
1885 return angle::Result::Continue;
1886 }
1887
1888 TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(mState.getCurrentTransformFeedback());
1889
1890 if (mState.isTransformFeedbackActiveUnpaused())
1891 {
1892 size_t bufferCount = executable->getTransformFeedbackBufferCount();
1893 const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &bufferHelpers =
1894 transformFeedbackVk->getBufferHelpers();
1895
1896 for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
1897 {
1898 vk::BufferHelper *bufferHelper = bufferHelpers[bufferIndex];
1899 ASSERT(bufferHelper);
1900 mRenderPassCommands->bufferWrite(this, VK_ACCESS_SHADER_WRITE_BIT,
1901 vk::PipelineStage::VertexShader,
1902 vk::AliasingMode::Disallowed, bufferHelper);
1903 }
1904 }
1905
1906 // TODO(http://anglebug.com/3570): Need to update to handle Program Pipelines
1907 vk::BufferHelper *uniformBuffer = mDefaultUniformStorage.getCurrentBuffer();
1908 vk::UniformsAndXfbDescriptorDesc xfbBufferDesc =
1909 transformFeedbackVk->getTransformFeedbackDesc();
1910 xfbBufferDesc.updateDefaultUniformBuffer(uniformBuffer ? uniformBuffer->getBufferSerial()
1911 : vk::kInvalidBufferSerial);
1912
1913 return mProgram->getExecutable().updateTransformFeedbackDescriptorSet(
1914 mProgram->getState(), mProgram->getDefaultUniformBlocks(), uniformBuffer, this,
1915 xfbBufferDesc);
1916 }
1917
handleDirtyGraphicsTransformFeedbackBuffersExtension(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1918 angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffersExtension(
1919 DirtyBits::Iterator *dirtyBitsIterator,
1920 DirtyBits dirtyBitMask)
1921 {
1922 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1923 ASSERT(executable);
1924
1925 if (!executable->hasTransformFeedbackOutput() || !mState.isTransformFeedbackActive())
1926 {
1927 return angle::Result::Continue;
1928 }
1929
1930 TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(mState.getCurrentTransformFeedback());
1931 size_t bufferCount = executable->getTransformFeedbackBufferCount();
1932
1933 const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &buffers =
1934 transformFeedbackVk->getBufferHelpers();
1935 gl::TransformFeedbackBuffersArray<vk::BufferHelper> &counterBuffers =
1936 transformFeedbackVk->getCounterBufferHelpers();
1937
1938 // Issue necessary barriers for the transform feedback buffers.
1939 for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
1940 {
1941 vk::BufferHelper *bufferHelper = buffers[bufferIndex];
1942 ASSERT(bufferHelper);
1943 mRenderPassCommands->bufferWrite(this, VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT,
1944 vk::PipelineStage::TransformFeedback,
1945 vk::AliasingMode::Disallowed, bufferHelper);
1946 }
1947
1948 // Issue necessary barriers for the transform feedback counter buffer. Note that the barrier is
1949 // issued only on the first buffer (which uses a global memory barrier), as all the counter
1950 // buffers of the transform feedback object are used together.
1951 ASSERT(counterBuffers[0].valid());
1952 mRenderPassCommands->bufferWrite(this,
1953 VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT |
1954 VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT,
1955 vk::PipelineStage::TransformFeedback,
1956 vk::AliasingMode::Disallowed, &counterBuffers[0]);
1957
1958 const gl::TransformFeedbackBuffersArray<VkBuffer> &bufferHandles =
1959 transformFeedbackVk->getBufferHandles();
1960 const gl::TransformFeedbackBuffersArray<VkDeviceSize> &bufferOffsets =
1961 transformFeedbackVk->getBufferOffsets();
1962 const gl::TransformFeedbackBuffersArray<VkDeviceSize> &bufferSizes =
1963 transformFeedbackVk->getBufferSizes();
1964
1965 mRenderPassCommandBuffer->bindTransformFeedbackBuffers(
1966 0, static_cast<uint32_t>(bufferCount), bufferHandles.data(), bufferOffsets.data(),
1967 bufferSizes.data());
1968
1969 if (!mState.isTransformFeedbackActiveUnpaused())
1970 {
1971 return angle::Result::Continue;
1972 }
1973
1974 // We should have same number of counter buffers as xfb buffers have
1975 const gl::TransformFeedbackBuffersArray<VkBuffer> &counterBufferHandles =
1976 transformFeedbackVk->getCounterBufferHandles();
1977
1978 bool rebindBuffers = transformFeedbackVk->getAndResetBufferRebindState();
1979
1980 mRenderPassCommands->beginTransformFeedback(bufferCount, counterBufferHandles.data(),
1981 rebindBuffers);
1982
1983 return angle::Result::Continue;
1984 }
1985
handleDirtyGraphicsTransformFeedbackResume(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1986 angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackResume(
1987 DirtyBits::Iterator *dirtyBitsIterator,
1988 DirtyBits dirtyBitMask)
1989 {
1990 if (mRenderPassCommands->isTransformFeedbackStarted())
1991 {
1992 mRenderPassCommands->resumeTransformFeedback();
1993 }
1994 return angle::Result::Continue;
1995 }
1996
handleDirtyGraphicsDescriptorSets(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1997 angle::Result ContextVk::handleDirtyGraphicsDescriptorSets(DirtyBits::Iterator *dirtyBitsIterator,
1998 DirtyBits dirtyBitMask)
1999 {
2000 return handleDirtyDescriptorSetsImpl(mRenderPassCommandBuffer);
2001 }
2002
handleDirtyGraphicsViewport(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2003 angle::Result ContextVk::handleDirtyGraphicsViewport(DirtyBits::Iterator *dirtyBitsIterator,
2004 DirtyBits dirtyBitMask)
2005 {
2006 mRenderPassCommandBuffer->setViewport(0, 1, &mViewport);
2007 return angle::Result::Continue;
2008 }
2009
handleDirtyGraphicsScissor(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2010 angle::Result ContextVk::handleDirtyGraphicsScissor(DirtyBits::Iterator *dirtyBitsIterator,
2011 DirtyBits dirtyBitMask)
2012 {
2013 handleDirtyGraphicsScissorImpl(mState.isQueryActive(gl::QueryType::PrimitivesGenerated));
2014 return angle::Result::Continue;
2015 }
2016
handleDirtyGraphicsScissorImpl(bool isPrimitivesGeneratedQueryActive)2017 void ContextVk::handleDirtyGraphicsScissorImpl(bool isPrimitivesGeneratedQueryActive)
2018 {
2019 // If primitives generated query and rasterizer discard are both active, but the Vulkan
2020 // implementation of the query does not support rasterizer discard, use an empty scissor to
2021 // emulate it.
2022 if (isEmulatingRasterizerDiscardDuringPrimitivesGeneratedQuery(
2023 isPrimitivesGeneratedQueryActive))
2024 {
2025 VkRect2D emptyScissor = {};
2026 mRenderPassCommandBuffer->setScissor(0, 1, &emptyScissor);
2027 }
2028 else
2029 {
2030 mRenderPassCommandBuffer->setScissor(0, 1, &mScissor);
2031 }
2032 }
2033
handleDirtyComputeDescriptorSets()2034 angle::Result ContextVk::handleDirtyComputeDescriptorSets()
2035 {
2036 return handleDirtyDescriptorSetsImpl(&mOutsideRenderPassCommands->getCommandBuffer());
2037 }
2038
handleDirtyDescriptorSetsImpl(vk::CommandBuffer * commandBuffer)2039 angle::Result ContextVk::handleDirtyDescriptorSetsImpl(vk::CommandBuffer *commandBuffer)
2040 {
2041 return mExecutable->updateDescriptorSets(this, commandBuffer);
2042 }
2043
syncObjectPerfCounters()2044 void ContextVk::syncObjectPerfCounters()
2045 {
2046 mPerfCounters.descriptorSetAllocations = 0;
2047 mPerfCounters.shaderBuffersDescriptorSetCacheHits = 0;
2048 mPerfCounters.shaderBuffersDescriptorSetCacheMisses = 0;
2049
2050 // ContextVk's descriptor set allocations
2051 ContextVkPerfCounters contextCounters = getAndResetObjectPerfCounters();
2052 for (uint32_t count : contextCounters.descriptorSetsAllocated)
2053 {
2054 mPerfCounters.descriptorSetAllocations += count;
2055 }
2056 // UtilsVk's descriptor set allocations
2057 mPerfCounters.descriptorSetAllocations +=
2058 mUtils.getAndResetObjectPerfCounters().descriptorSetsAllocated;
2059 // ProgramExecutableVk's descriptor set allocations
2060 const gl::State &state = getState();
2061 const gl::ShaderProgramManager &shadersAndPrograms = state.getShaderProgramManagerForCapture();
2062 const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programs =
2063 shadersAndPrograms.getProgramsForCaptureAndPerf();
2064 for (const std::pair<GLuint, gl::Program *> &resource : programs)
2065 {
2066 gl::Program *program = resource.second;
2067 if (program->hasLinkingState())
2068 {
2069 continue;
2070 }
2071 ProgramVk *programVk = vk::GetImpl(resource.second);
2072 ProgramExecutablePerfCounters progPerfCounters =
2073 programVk->getExecutable().getAndResetObjectPerfCounters();
2074
2075 for (uint32_t count : progPerfCounters.descriptorSetAllocations)
2076 {
2077 mPerfCounters.descriptorSetAllocations += count;
2078 }
2079
2080 mPerfCounters.shaderBuffersDescriptorSetCacheHits +=
2081 progPerfCounters.descriptorSetCacheHits[DescriptorSetIndex::ShaderResource];
2082 mPerfCounters.shaderBuffersDescriptorSetCacheMisses +=
2083 progPerfCounters.descriptorSetCacheMisses[DescriptorSetIndex::ShaderResource];
2084 }
2085 }
2086
updateOverlayOnPresent()2087 void ContextVk::updateOverlayOnPresent()
2088 {
2089 const gl::OverlayType *overlay = mState.getOverlay();
2090 ASSERT(overlay->isEnabled());
2091
2092 syncObjectPerfCounters();
2093
2094 // Update overlay if active.
2095 {
2096 gl::RunningGraphWidget *renderPassCount =
2097 overlay->getRunningGraphWidget(gl::WidgetId::VulkanRenderPassCount);
2098 renderPassCount->add(mRenderPassCommands->getAndResetCounter());
2099 renderPassCount->next();
2100 }
2101
2102 {
2103 gl::RunningGraphWidget *writeDescriptorSetCount =
2104 overlay->getRunningGraphWidget(gl::WidgetId::VulkanWriteDescriptorSetCount);
2105 writeDescriptorSetCount->add(mPerfCounters.writeDescriptorSets);
2106 writeDescriptorSetCount->next();
2107
2108 mPerfCounters.writeDescriptorSets = 0;
2109 }
2110
2111 {
2112 gl::RunningGraphWidget *descriptorSetAllocationCount =
2113 overlay->getRunningGraphWidget(gl::WidgetId::VulkanDescriptorSetAllocations);
2114 descriptorSetAllocationCount->add(mPerfCounters.descriptorSetAllocations);
2115 descriptorSetAllocationCount->next();
2116 }
2117
2118 {
2119 gl::RunningGraphWidget *shaderBufferHitRate =
2120 overlay->getRunningGraphWidget(gl::WidgetId::VulkanShaderBufferDSHitRate);
2121 size_t numCacheAccesses = mPerfCounters.shaderBuffersDescriptorSetCacheHits +
2122 mPerfCounters.shaderBuffersDescriptorSetCacheMisses;
2123 if (numCacheAccesses > 0)
2124 {
2125 float hitRateFloat =
2126 static_cast<float>(mPerfCounters.shaderBuffersDescriptorSetCacheHits) /
2127 static_cast<float>(numCacheAccesses);
2128 size_t hitRate = static_cast<size_t>(hitRateFloat * 100.0f);
2129 shaderBufferHitRate->add(hitRate);
2130 shaderBufferHitRate->next();
2131 }
2132 }
2133
2134 {
2135 gl::RunningGraphWidget *dynamicBufferAllocations =
2136 overlay->getRunningGraphWidget(gl::WidgetId::VulkanDynamicBufferAllocations);
2137 dynamicBufferAllocations->next();
2138 }
2139 }
2140
addOverlayUsedBuffersCount(vk::CommandBufferHelper * commandBuffer)2141 void ContextVk::addOverlayUsedBuffersCount(vk::CommandBufferHelper *commandBuffer)
2142 {
2143 const gl::OverlayType *overlay = mState.getOverlay();
2144 if (!overlay->isEnabled())
2145 {
2146 return;
2147 }
2148
2149 gl::RunningHistogramWidget *widget =
2150 overlay->getRunningHistogramWidget(gl::WidgetId::VulkanRenderPassBufferCount);
2151 size_t buffersCount = commandBuffer->getUsedBuffersCount();
2152 if (buffersCount > 0)
2153 {
2154 widget->add(buffersCount);
2155 widget->next();
2156 }
2157 }
2158
submitFrame(const vk::Semaphore * signalSemaphore)2159 angle::Result ContextVk::submitFrame(const vk::Semaphore *signalSemaphore)
2160 {
2161 if (mCurrentWindowSurface)
2162 {
2163 vk::Semaphore waitSemaphore = mCurrentWindowSurface->getAcquireImageSemaphore();
2164 if (waitSemaphore.valid())
2165 {
2166 addWaitSemaphore(waitSemaphore.getHandle(),
2167 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2168 addGarbage(&waitSemaphore);
2169 }
2170 }
2171
2172 if (vk::CommandBufferHelper::kEnableCommandStreamDiagnostics)
2173 {
2174 dumpCommandStreamDiagnostics();
2175 }
2176
2177 getShareGroupVk()->acquireResourceUseList(std::move(mResourceUseList));
2178 ANGLE_TRY(mRenderer->submitFrame(
2179 this, hasProtectedContent(), mContextPriority, std::move(mWaitSemaphores),
2180 std::move(mWaitSemaphoreStageMasks), signalSemaphore,
2181 getShareGroupVk()->releaseResourceUseLists(), std::move(mCurrentGarbage), &mCommandPool));
2182
2183 onRenderPassFinished();
2184 mComputeDirtyBits |= mNewComputeCommandBufferDirtyBits;
2185
2186 if (mGpuEventsEnabled)
2187 {
2188 ANGLE_TRY(checkCompletedGpuEvents());
2189 }
2190
2191 return angle::Result::Continue;
2192 }
2193
synchronizeCpuGpuTime()2194 angle::Result ContextVk::synchronizeCpuGpuTime()
2195 {
2196 ASSERT(mGpuEventsEnabled);
2197
2198 angle::PlatformMethods *platform = ANGLEPlatformCurrent();
2199 ASSERT(platform);
2200
2201 // To synchronize CPU and GPU times, we need to get the CPU timestamp as close as possible
2202 // to the GPU timestamp. The process of getting the GPU timestamp is as follows:
2203 //
2204 // CPU GPU
2205 //
2206 // Record command buffer
2207 // with timestamp query
2208 //
2209 // Submit command buffer
2210 //
2211 // Post-submission work Begin execution
2212 //
2213 // ???? Write timestamp Tgpu
2214 //
2215 // ???? End execution
2216 //
2217 // ???? Return query results
2218 //
2219 // ????
2220 //
2221 // Get query results
2222 //
2223 // The areas of unknown work (????) on the CPU indicate that the CPU may or may not have
2224 // finished post-submission work while the GPU is executing in parallel. With no further
2225 // work, querying CPU timestamps before submission and after getting query results give the
2226 // bounds to Tgpu, which could be quite large.
2227 //
2228 // Using VkEvents, the GPU can be made to wait for the CPU and vice versa, in an effort to
2229 // reduce this range. This function implements the following procedure:
2230 //
2231 // CPU GPU
2232 //
2233 // Record command buffer
2234 // with timestamp query
2235 //
2236 // Submit command buffer
2237 //
2238 // Post-submission work Begin execution
2239 //
2240 // ???? Set Event GPUReady
2241 //
2242 // Wait on Event GPUReady Wait on Event CPUReady
2243 //
2244 // Get CPU Time Ts Wait on Event CPUReady
2245 //
2246 // Set Event CPUReady Wait on Event CPUReady
2247 //
2248 // Get CPU Time Tcpu Get GPU Time Tgpu
2249 //
2250 // Wait on Event GPUDone Set Event GPUDone
2251 //
2252 // Get CPU Time Te End Execution
2253 //
2254 // Idle Return query results
2255 //
2256 // Get query results
2257 //
2258 // If Te-Ts > epsilon, a GPU or CPU interruption can be assumed and the operation can be
2259 // retried. Once Te-Ts < epsilon, Tcpu can be taken to presumably match Tgpu. Finding an
2260 // epsilon that's valid for all devices may be difficult, so the loop can be performed only
2261 // a limited number of times and the Tcpu,Tgpu pair corresponding to smallest Te-Ts used for
2262 // calibration.
2263 //
2264 // Note: Once VK_EXT_calibrated_timestamps is ubiquitous, this should be redone.
2265
2266 // Make sure nothing is running
2267 ASSERT(!hasRecordedCommands());
2268
2269 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::synchronizeCpuGpuTime");
2270
2271 // Create a query used to receive the GPU timestamp
2272 vk::QueryHelper timestampQuery;
2273 ANGLE_TRY(mGpuEventQueryPool.allocateQuery(this, ×tampQuery, 1));
2274
2275 // Create the three events
2276 VkEventCreateInfo eventCreateInfo = {};
2277 eventCreateInfo.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
2278 eventCreateInfo.flags = 0;
2279
2280 VkDevice device = getDevice();
2281 vk::DeviceScoped<vk::Event> cpuReady(device), gpuReady(device), gpuDone(device);
2282 ANGLE_VK_TRY(this, cpuReady.get().init(device, eventCreateInfo));
2283 ANGLE_VK_TRY(this, gpuReady.get().init(device, eventCreateInfo));
2284 ANGLE_VK_TRY(this, gpuDone.get().init(device, eventCreateInfo));
2285
2286 constexpr uint32_t kRetries = 10;
2287
2288 // Time suffixes used are S for seconds and Cycles for cycles
2289 double tightestRangeS = 1e6f;
2290 double TcpuS = 0;
2291 uint64_t TgpuCycles = 0;
2292 for (uint32_t i = 0; i < kRetries; ++i)
2293 {
2294 // Reset the events
2295 ANGLE_VK_TRY(this, cpuReady.get().reset(device));
2296 ANGLE_VK_TRY(this, gpuReady.get().reset(device));
2297 ANGLE_VK_TRY(this, gpuDone.get().reset(device));
2298
2299 // Record the command buffer
2300 vk::DeviceScoped<vk::PrimaryCommandBuffer> commandBatch(device);
2301 vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get();
2302
2303 vk::ResourceUseList scratchResourceUseList;
2304
2305 ANGLE_TRY(mRenderer->getCommandBufferOneOff(this, hasProtectedContent(), &commandBuffer));
2306
2307 commandBuffer.setEvent(gpuReady.get().getHandle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
2308 commandBuffer.waitEvents(1, cpuReady.get().ptr(), VK_PIPELINE_STAGE_HOST_BIT,
2309 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, nullptr, 0, nullptr, 0,
2310 nullptr);
2311 timestampQuery.writeTimestampToPrimary(this, &commandBuffer);
2312 timestampQuery.retain(&scratchResourceUseList);
2313
2314 commandBuffer.setEvent(gpuDone.get().getHandle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
2315
2316 ANGLE_VK_TRY(this, commandBuffer.end());
2317
2318 Serial throwAwaySerial;
2319 // vkEvent's are externally synchronized, therefore need work to be submitted before calling
2320 // vkGetEventStatus
2321 ANGLE_TRY(mRenderer->queueSubmitOneOff(
2322 this, std::move(commandBuffer), hasProtectedContent(), mContextPriority, nullptr,
2323 vk::SubmitPolicy::EnsureSubmitted, &throwAwaySerial));
2324 scratchResourceUseList.releaseResourceUsesAndUpdateSerials(throwAwaySerial);
2325
2326 // Wait for GPU to be ready. This is a short busy wait.
2327 VkResult result = VK_EVENT_RESET;
2328 do
2329 {
2330 result = gpuReady.get().getStatus(device);
2331 if (result != VK_EVENT_SET && result != VK_EVENT_RESET)
2332 {
2333 ANGLE_VK_TRY(this, result);
2334 }
2335 } while (result == VK_EVENT_RESET);
2336
2337 double TsS = platform->monotonicallyIncreasingTime(platform);
2338
2339 // Tell the GPU to go ahead with the timestamp query.
2340 ANGLE_VK_TRY(this, cpuReady.get().set(device));
2341 double cpuTimestampS = platform->monotonicallyIncreasingTime(platform);
2342
2343 // Wait for GPU to be done. Another short busy wait.
2344 do
2345 {
2346 result = gpuDone.get().getStatus(device);
2347 if (result != VK_EVENT_SET && result != VK_EVENT_RESET)
2348 {
2349 ANGLE_VK_TRY(this, result);
2350 }
2351 } while (result == VK_EVENT_RESET);
2352
2353 double TeS = platform->monotonicallyIncreasingTime(platform);
2354
2355 // Get the query results
2356 // Note: This LastSubmittedQueueSerial may include more work then was submitted above if
2357 // another thread had submitted work.
2358 ANGLE_TRY(finishToSerial(getLastSubmittedQueueSerial()));
2359
2360 vk::QueryResult gpuTimestampCycles(1);
2361 ANGLE_TRY(timestampQuery.getUint64Result(this, &gpuTimestampCycles));
2362
2363 // Use the first timestamp queried as origin.
2364 if (mGpuEventTimestampOrigin == 0)
2365 {
2366 mGpuEventTimestampOrigin =
2367 gpuTimestampCycles.getResult(vk::QueryResult::kDefaultResultIndex);
2368 }
2369
2370 // Take these CPU and GPU timestamps if there is better confidence.
2371 double confidenceRangeS = TeS - TsS;
2372 if (confidenceRangeS < tightestRangeS)
2373 {
2374 tightestRangeS = confidenceRangeS;
2375 TcpuS = cpuTimestampS;
2376 TgpuCycles = gpuTimestampCycles.getResult(vk::QueryResult::kDefaultResultIndex);
2377 }
2378 }
2379
2380 mGpuEventQueryPool.freeQuery(this, ×tampQuery);
2381
2382 // timestampPeriod gives nanoseconds/cycle.
2383 double TgpuS =
2384 (TgpuCycles - mGpuEventTimestampOrigin) *
2385 static_cast<double>(getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod) /
2386 1'000'000'000.0;
2387
2388 flushGpuEvents(TgpuS, TcpuS);
2389
2390 mGpuClockSync.gpuTimestampS = TgpuS;
2391 mGpuClockSync.cpuTimestampS = TcpuS;
2392
2393 return angle::Result::Continue;
2394 }
2395
traceGpuEventImpl(vk::CommandBuffer * commandBuffer,char phase,const EventName & name)2396 angle::Result ContextVk::traceGpuEventImpl(vk::CommandBuffer *commandBuffer,
2397 char phase,
2398 const EventName &name)
2399 {
2400 ASSERT(mGpuEventsEnabled);
2401
2402 GpuEventQuery gpuEvent;
2403 gpuEvent.name = name;
2404 gpuEvent.phase = phase;
2405 ANGLE_TRY(mGpuEventQueryPool.allocateQuery(this, &gpuEvent.queryHelper, 1));
2406
2407 gpuEvent.queryHelper.writeTimestamp(this, commandBuffer);
2408
2409 mInFlightGpuEventQueries.push_back(std::move(gpuEvent));
2410 return angle::Result::Continue;
2411 }
2412
checkCompletedGpuEvents()2413 angle::Result ContextVk::checkCompletedGpuEvents()
2414 {
2415 ASSERT(mGpuEventsEnabled);
2416
2417 angle::PlatformMethods *platform = ANGLEPlatformCurrent();
2418 ASSERT(platform);
2419
2420 int finishedCount = 0;
2421
2422 Serial lastCompletedSerial = getLastCompletedQueueSerial();
2423
2424 for (GpuEventQuery &eventQuery : mInFlightGpuEventQueries)
2425 {
2426 // Only check the timestamp query if the submission has finished.
2427 if (eventQuery.queryHelper.usedInRunningCommands(lastCompletedSerial))
2428 {
2429 break;
2430 }
2431
2432 // See if the results are available.
2433 vk::QueryResult gpuTimestampCycles(1);
2434 bool available = false;
2435 ANGLE_TRY(eventQuery.queryHelper.getUint64ResultNonBlocking(this, &gpuTimestampCycles,
2436 &available));
2437 if (!available)
2438 {
2439 break;
2440 }
2441
2442 mGpuEventQueryPool.freeQuery(this, &eventQuery.queryHelper);
2443
2444 GpuEvent gpuEvent;
2445 gpuEvent.gpuTimestampCycles =
2446 gpuTimestampCycles.getResult(vk::QueryResult::kDefaultResultIndex);
2447 gpuEvent.name = eventQuery.name;
2448 gpuEvent.phase = eventQuery.phase;
2449
2450 mGpuEvents.emplace_back(gpuEvent);
2451
2452 ++finishedCount;
2453 }
2454
2455 mInFlightGpuEventQueries.erase(mInFlightGpuEventQueries.begin(),
2456 mInFlightGpuEventQueries.begin() + finishedCount);
2457
2458 return angle::Result::Continue;
2459 }
2460
flushGpuEvents(double nextSyncGpuTimestampS,double nextSyncCpuTimestampS)2461 void ContextVk::flushGpuEvents(double nextSyncGpuTimestampS, double nextSyncCpuTimestampS)
2462 {
2463 if (mGpuEvents.empty())
2464 {
2465 return;
2466 }
2467
2468 angle::PlatformMethods *platform = ANGLEPlatformCurrent();
2469 ASSERT(platform);
2470
2471 // Find the slope of the clock drift for adjustment
2472 double lastGpuSyncTimeS = mGpuClockSync.gpuTimestampS;
2473 double lastGpuSyncDiffS = mGpuClockSync.cpuTimestampS - mGpuClockSync.gpuTimestampS;
2474 double gpuSyncDriftSlope = 0;
2475
2476 double nextGpuSyncTimeS = nextSyncGpuTimestampS;
2477 double nextGpuSyncDiffS = nextSyncCpuTimestampS - nextSyncGpuTimestampS;
2478
2479 // No gpu trace events should have been generated before the clock sync, so if there is no
2480 // "previous" clock sync, there should be no gpu events (i.e. the function early-outs
2481 // above).
2482 ASSERT(mGpuClockSync.gpuTimestampS != std::numeric_limits<double>::max() &&
2483 mGpuClockSync.cpuTimestampS != std::numeric_limits<double>::max());
2484
2485 gpuSyncDriftSlope =
2486 (nextGpuSyncDiffS - lastGpuSyncDiffS) / (nextGpuSyncTimeS - lastGpuSyncTimeS);
2487
2488 for (const GpuEvent &gpuEvent : mGpuEvents)
2489 {
2490 double gpuTimestampS =
2491 (gpuEvent.gpuTimestampCycles - mGpuEventTimestampOrigin) *
2492 static_cast<double>(
2493 getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod) *
2494 1e-9;
2495
2496 // Account for clock drift.
2497 gpuTimestampS += lastGpuSyncDiffS + gpuSyncDriftSlope * (gpuTimestampS - lastGpuSyncTimeS);
2498
2499 // Generate the trace now that the GPU timestamp is available and clock drifts are
2500 // accounted for.
2501 static long long eventId = 1;
2502 static const unsigned char *categoryEnabled =
2503 TRACE_EVENT_API_GET_CATEGORY_ENABLED(platform, "gpu.angle.gpu");
2504 platform->addTraceEvent(platform, gpuEvent.phase, categoryEnabled, gpuEvent.name.data(),
2505 eventId++, gpuTimestampS, 0, nullptr, nullptr, nullptr,
2506 TRACE_EVENT_FLAG_NONE);
2507 }
2508
2509 mGpuEvents.clear();
2510 }
2511
clearAllGarbage()2512 void ContextVk::clearAllGarbage()
2513 {
2514 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::clearAllGarbage");
2515 for (vk::GarbageObject &garbage : mCurrentGarbage)
2516 {
2517 garbage.destroy(mRenderer);
2518 }
2519 mCurrentGarbage.clear();
2520 }
2521
handleDeviceLost()2522 void ContextVk::handleDeviceLost()
2523 {
2524 mOutsideRenderPassCommands->reset();
2525 mRenderPassCommands->reset();
2526 mRenderer->handleDeviceLost();
2527 clearAllGarbage();
2528
2529 mRenderer->notifyDeviceLost();
2530 }
2531
drawArrays(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count)2532 angle::Result ContextVk::drawArrays(const gl::Context *context,
2533 gl::PrimitiveMode mode,
2534 GLint first,
2535 GLsizei count)
2536 {
2537 uint32_t clampedVertexCount = gl::GetClampedVertexCount<uint32_t>(count);
2538
2539 if (mode == gl::PrimitiveMode::LineLoop)
2540 {
2541 uint32_t numIndices;
2542 ANGLE_TRY(setupLineLoopDraw(context, mode, first, count, gl::DrawElementsType::InvalidEnum,
2543 nullptr, &numIndices));
2544 vk::LineLoopHelper::Draw(numIndices, 0, mRenderPassCommandBuffer);
2545 }
2546 else
2547 {
2548 ANGLE_TRY(setupDraw(context, mode, first, count, 1, gl::DrawElementsType::InvalidEnum,
2549 nullptr, mNonIndexedDirtyBitsMask));
2550 mRenderPassCommandBuffer->draw(clampedVertexCount, first);
2551 }
2552
2553 return angle::Result::Continue;
2554 }
2555
drawArraysInstanced(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instances)2556 angle::Result ContextVk::drawArraysInstanced(const gl::Context *context,
2557 gl::PrimitiveMode mode,
2558 GLint first,
2559 GLsizei count,
2560 GLsizei instances)
2561 {
2562 if (mode == gl::PrimitiveMode::LineLoop)
2563 {
2564 uint32_t clampedVertexCount = gl::GetClampedVertexCount<uint32_t>(count);
2565 uint32_t numIndices;
2566 ANGLE_TRY(setupLineLoopDraw(context, mode, first, clampedVertexCount,
2567 gl::DrawElementsType::InvalidEnum, nullptr, &numIndices));
2568 mRenderPassCommandBuffer->drawIndexedInstanced(numIndices, instances);
2569 return angle::Result::Continue;
2570 }
2571
2572 ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum,
2573 nullptr, mNonIndexedDirtyBitsMask));
2574 mRenderPassCommandBuffer->drawInstanced(gl::GetClampedVertexCount<uint32_t>(count), instances,
2575 first);
2576 return angle::Result::Continue;
2577 }
2578
drawArraysInstancedBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instances,GLuint baseInstance)2579 angle::Result ContextVk::drawArraysInstancedBaseInstance(const gl::Context *context,
2580 gl::PrimitiveMode mode,
2581 GLint first,
2582 GLsizei count,
2583 GLsizei instances,
2584 GLuint baseInstance)
2585 {
2586 if (mode == gl::PrimitiveMode::LineLoop)
2587 {
2588 uint32_t clampedVertexCount = gl::GetClampedVertexCount<uint32_t>(count);
2589 uint32_t numIndices;
2590 ANGLE_TRY(setupLineLoopDraw(context, mode, first, clampedVertexCount,
2591 gl::DrawElementsType::InvalidEnum, nullptr, &numIndices));
2592 mRenderPassCommandBuffer->drawIndexedInstancedBaseVertexBaseInstance(numIndices, instances,
2593 0, 0, baseInstance);
2594 return angle::Result::Continue;
2595 }
2596
2597 ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum,
2598 nullptr, mNonIndexedDirtyBitsMask));
2599 mRenderPassCommandBuffer->drawInstancedBaseInstance(gl::GetClampedVertexCount<uint32_t>(count),
2600 instances, first, baseInstance);
2601 return angle::Result::Continue;
2602 }
2603
drawElements(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices)2604 angle::Result ContextVk::drawElements(const gl::Context *context,
2605 gl::PrimitiveMode mode,
2606 GLsizei count,
2607 gl::DrawElementsType type,
2608 const void *indices)
2609 {
2610 if (mode == gl::PrimitiveMode::LineLoop)
2611 {
2612 uint32_t indexCount;
2613 ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &indexCount));
2614 vk::LineLoopHelper::Draw(indexCount, 0, mRenderPassCommandBuffer);
2615 }
2616 else
2617 {
2618 ANGLE_TRY(setupIndexedDraw(context, mode, count, 1, type, indices));
2619 mRenderPassCommandBuffer->drawIndexed(count);
2620 }
2621
2622 return angle::Result::Continue;
2623 }
2624
drawElementsBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLint baseVertex)2625 angle::Result ContextVk::drawElementsBaseVertex(const gl::Context *context,
2626 gl::PrimitiveMode mode,
2627 GLsizei count,
2628 gl::DrawElementsType type,
2629 const void *indices,
2630 GLint baseVertex)
2631 {
2632 if (mode == gl::PrimitiveMode::LineLoop)
2633 {
2634 uint32_t indexCount;
2635 ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &indexCount));
2636 vk::LineLoopHelper::Draw(indexCount, baseVertex, mRenderPassCommandBuffer);
2637 }
2638 else
2639 {
2640 ANGLE_TRY(setupIndexedDraw(context, mode, count, 1, type, indices));
2641 mRenderPassCommandBuffer->drawIndexedBaseVertex(count, baseVertex);
2642 }
2643
2644 return angle::Result::Continue;
2645 }
2646
drawElementsInstanced(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances)2647 angle::Result ContextVk::drawElementsInstanced(const gl::Context *context,
2648 gl::PrimitiveMode mode,
2649 GLsizei count,
2650 gl::DrawElementsType type,
2651 const void *indices,
2652 GLsizei instances)
2653 {
2654 if (mode == gl::PrimitiveMode::LineLoop)
2655 {
2656 uint32_t indexCount;
2657 ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &indexCount));
2658 count = indexCount;
2659 }
2660 else
2661 {
2662 ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices));
2663 }
2664
2665 mRenderPassCommandBuffer->drawIndexedInstanced(count, instances);
2666 return angle::Result::Continue;
2667 }
2668
drawElementsInstancedBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances,GLint baseVertex)2669 angle::Result ContextVk::drawElementsInstancedBaseVertex(const gl::Context *context,
2670 gl::PrimitiveMode mode,
2671 GLsizei count,
2672 gl::DrawElementsType type,
2673 const void *indices,
2674 GLsizei instances,
2675 GLint baseVertex)
2676 {
2677 if (mode == gl::PrimitiveMode::LineLoop)
2678 {
2679 uint32_t indexCount;
2680 ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &indexCount));
2681 count = indexCount;
2682 }
2683 else
2684 {
2685 ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices));
2686 }
2687
2688 mRenderPassCommandBuffer->drawIndexedInstancedBaseVertex(count, instances, baseVertex);
2689 return angle::Result::Continue;
2690 }
2691
drawElementsInstancedBaseVertexBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances,GLint baseVertex,GLuint baseInstance)2692 angle::Result ContextVk::drawElementsInstancedBaseVertexBaseInstance(const gl::Context *context,
2693 gl::PrimitiveMode mode,
2694 GLsizei count,
2695 gl::DrawElementsType type,
2696 const void *indices,
2697 GLsizei instances,
2698 GLint baseVertex,
2699 GLuint baseInstance)
2700 {
2701 if (mode == gl::PrimitiveMode::LineLoop)
2702 {
2703 uint32_t indexCount;
2704 ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &indexCount));
2705 mRenderPassCommandBuffer->drawIndexedInstancedBaseVertexBaseInstance(
2706 indexCount, instances, 0, baseVertex, baseInstance);
2707 return angle::Result::Continue;
2708 }
2709
2710 ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices));
2711 mRenderPassCommandBuffer->drawIndexedInstancedBaseVertexBaseInstance(count, instances, 0,
2712 baseVertex, baseInstance);
2713 return angle::Result::Continue;
2714 }
2715
drawRangeElements(const gl::Context * context,gl::PrimitiveMode mode,GLuint start,GLuint end,GLsizei count,gl::DrawElementsType type,const void * indices)2716 angle::Result ContextVk::drawRangeElements(const gl::Context *context,
2717 gl::PrimitiveMode mode,
2718 GLuint start,
2719 GLuint end,
2720 GLsizei count,
2721 gl::DrawElementsType type,
2722 const void *indices)
2723 {
2724 return drawElements(context, mode, count, type, indices);
2725 }
2726
drawRangeElementsBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLuint start,GLuint end,GLsizei count,gl::DrawElementsType type,const void * indices,GLint baseVertex)2727 angle::Result ContextVk::drawRangeElementsBaseVertex(const gl::Context *context,
2728 gl::PrimitiveMode mode,
2729 GLuint start,
2730 GLuint end,
2731 GLsizei count,
2732 gl::DrawElementsType type,
2733 const void *indices,
2734 GLint baseVertex)
2735 {
2736 return drawElementsBaseVertex(context, mode, count, type, indices, baseVertex);
2737 }
2738
getDevice() const2739 VkDevice ContextVk::getDevice() const
2740 {
2741 return mRenderer->getDevice();
2742 }
2743
drawArraysIndirect(const gl::Context * context,gl::PrimitiveMode mode,const void * indirect)2744 angle::Result ContextVk::drawArraysIndirect(const gl::Context *context,
2745 gl::PrimitiveMode mode,
2746 const void *indirect)
2747 {
2748 gl::Buffer *indirectBuffer = mState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
2749 VkDeviceSize indirectBufferOffset = 0;
2750 vk::BufferHelper *currentIndirectBuf =
2751 &vk::GetImpl(indirectBuffer)->getBufferAndOffset(&indirectBufferOffset);
2752 VkDeviceSize currentIndirectBufOffset =
2753 indirectBufferOffset + reinterpret_cast<VkDeviceSize>(indirect);
2754
2755 if (mVertexArray->getStreamingVertexAttribsMask().any())
2756 {
2757 // We have instanced vertex attributes that need to be emulated for Vulkan.
2758 // invalidate any cache and map the buffer so that we can read the indirect data.
2759 // Mapping the buffer will cause a flush.
2760 ANGLE_TRY(currentIndirectBuf->invalidate(mRenderer, 0, sizeof(VkDrawIndirectCommand)));
2761 uint8_t *buffPtr;
2762 ANGLE_TRY(currentIndirectBuf->map(this, &buffPtr));
2763 const VkDrawIndirectCommand *indirectData =
2764 reinterpret_cast<VkDrawIndirectCommand *>(buffPtr + currentIndirectBufOffset);
2765
2766 ANGLE_TRY(drawArraysInstanced(context, mode, indirectData->firstVertex,
2767 indirectData->vertexCount, indirectData->instanceCount));
2768
2769 currentIndirectBuf->unmap(mRenderer);
2770 return angle::Result::Continue;
2771 }
2772
2773 if (mode == gl::PrimitiveMode::LineLoop)
2774 {
2775 ASSERT(indirectBuffer);
2776 vk::BufferHelper *dstIndirectBuf = nullptr;
2777 VkDeviceSize dstIndirectBufOffset = 0;
2778
2779 ANGLE_TRY(setupLineLoopIndirectDraw(context, mode, currentIndirectBuf,
2780 currentIndirectBufOffset, &dstIndirectBuf,
2781 &dstIndirectBufOffset));
2782
2783 mRenderPassCommandBuffer->drawIndexedIndirect(dstIndirectBuf->getBuffer(),
2784 dstIndirectBufOffset, 1, 0);
2785 return angle::Result::Continue;
2786 }
2787
2788 ANGLE_TRY(setupIndirectDraw(context, mode, mNonIndexedDirtyBitsMask, currentIndirectBuf,
2789 currentIndirectBufOffset));
2790
2791 mRenderPassCommandBuffer->drawIndirect(currentIndirectBuf->getBuffer(),
2792 currentIndirectBufOffset, 1, 0);
2793 return angle::Result::Continue;
2794 }
2795
drawElementsIndirect(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType type,const void * indirect)2796 angle::Result ContextVk::drawElementsIndirect(const gl::Context *context,
2797 gl::PrimitiveMode mode,
2798 gl::DrawElementsType type,
2799 const void *indirect)
2800 {
2801 gl::Buffer *indirectBuffer = mState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
2802 ASSERT(indirectBuffer);
2803 VkDeviceSize indirectBufferOffset = 0;
2804 vk::BufferHelper *currentIndirectBuf =
2805 &vk::GetImpl(indirectBuffer)->getBufferAndOffset(&indirectBufferOffset);
2806 VkDeviceSize currentIndirectBufOffset =
2807 indirectBufferOffset + reinterpret_cast<VkDeviceSize>(indirect);
2808
2809 if (mVertexArray->getStreamingVertexAttribsMask().any())
2810 {
2811 // We have instanced vertex attributes that need to be emulated for Vulkan.
2812 // invalidate any cache and map the buffer so that we can read the indirect data.
2813 // Mapping the buffer will cause a flush.
2814 ANGLE_TRY(
2815 currentIndirectBuf->invalidate(mRenderer, 0, sizeof(VkDrawIndexedIndirectCommand)));
2816 uint8_t *buffPtr;
2817 ANGLE_TRY(currentIndirectBuf->map(this, &buffPtr));
2818 const VkDrawIndexedIndirectCommand *indirectData =
2819 reinterpret_cast<VkDrawIndexedIndirectCommand *>(buffPtr + currentIndirectBufOffset);
2820
2821 ANGLE_TRY(drawElementsInstanced(context, mode, indirectData->indexCount, type, nullptr,
2822 indirectData->instanceCount));
2823
2824 currentIndirectBuf->unmap(mRenderer);
2825 return angle::Result::Continue;
2826 }
2827
2828 if (shouldConvertUint8VkIndexType(type) && mGraphicsDirtyBits[DIRTY_BIT_INDEX_BUFFER])
2829 {
2830 ANGLE_PERF_WARNING(getDebug(), GL_DEBUG_SEVERITY_LOW,
2831 "Potential inefficiency emulating uint8 vertex attributes due to lack "
2832 "of hardware support");
2833
2834 vk::BufferHelper *dstIndirectBuf;
2835 VkDeviceSize dstIndirectBufOffset;
2836
2837 ANGLE_TRY(mVertexArray->convertIndexBufferIndirectGPU(
2838 this, currentIndirectBuf, currentIndirectBufOffset, &dstIndirectBuf,
2839 &dstIndirectBufOffset));
2840
2841 currentIndirectBuf = dstIndirectBuf;
2842 currentIndirectBufOffset = dstIndirectBufOffset;
2843 }
2844
2845 if (mode == gl::PrimitiveMode::LineLoop)
2846 {
2847 vk::BufferHelper *dstIndirectBuf;
2848 VkDeviceSize dstIndirectBufOffset;
2849
2850 ANGLE_TRY(setupLineLoopIndexedIndirectDraw(context, mode, type, currentIndirectBuf,
2851 currentIndirectBufOffset, &dstIndirectBuf,
2852 &dstIndirectBufOffset));
2853
2854 currentIndirectBuf = dstIndirectBuf;
2855 currentIndirectBufOffset = dstIndirectBufOffset;
2856 }
2857 else
2858 {
2859 ANGLE_TRY(setupIndexedIndirectDraw(context, mode, type, currentIndirectBuf,
2860 currentIndirectBufOffset));
2861 }
2862
2863 mRenderPassCommandBuffer->drawIndexedIndirect(currentIndirectBuf->getBuffer(),
2864 currentIndirectBufOffset, 1, 0);
2865 return angle::Result::Continue;
2866 }
2867
multiDrawArrays(const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,GLsizei drawcount)2868 angle::Result ContextVk::multiDrawArrays(const gl::Context *context,
2869 gl::PrimitiveMode mode,
2870 const GLint *firsts,
2871 const GLsizei *counts,
2872 GLsizei drawcount)
2873 {
2874 return rx::MultiDrawArraysGeneral(this, context, mode, firsts, counts, drawcount);
2875 }
2876
multiDrawArraysInstanced(const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instanceCounts,GLsizei drawcount)2877 angle::Result ContextVk::multiDrawArraysInstanced(const gl::Context *context,
2878 gl::PrimitiveMode mode,
2879 const GLint *firsts,
2880 const GLsizei *counts,
2881 const GLsizei *instanceCounts,
2882 GLsizei drawcount)
2883 {
2884 return rx::MultiDrawArraysInstancedGeneral(this, context, mode, firsts, counts, instanceCounts,
2885 drawcount);
2886 }
2887
multiDrawElements(const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,GLsizei drawcount)2888 angle::Result ContextVk::multiDrawElements(const gl::Context *context,
2889 gl::PrimitiveMode mode,
2890 const GLsizei *counts,
2891 gl::DrawElementsType type,
2892 const GLvoid *const *indices,
2893 GLsizei drawcount)
2894 {
2895 return rx::MultiDrawElementsGeneral(this, context, mode, counts, type, indices, drawcount);
2896 }
2897
multiDrawElementsInstanced(const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,const GLsizei * instanceCounts,GLsizei drawcount)2898 angle::Result ContextVk::multiDrawElementsInstanced(const gl::Context *context,
2899 gl::PrimitiveMode mode,
2900 const GLsizei *counts,
2901 gl::DrawElementsType type,
2902 const GLvoid *const *indices,
2903 const GLsizei *instanceCounts,
2904 GLsizei drawcount)
2905 {
2906 return rx::MultiDrawElementsInstancedGeneral(this, context, mode, counts, type, indices,
2907 instanceCounts, drawcount);
2908 }
2909
multiDrawArraysInstancedBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instanceCounts,const GLuint * baseInstances,GLsizei drawcount)2910 angle::Result ContextVk::multiDrawArraysInstancedBaseInstance(const gl::Context *context,
2911 gl::PrimitiveMode mode,
2912 const GLint *firsts,
2913 const GLsizei *counts,
2914 const GLsizei *instanceCounts,
2915 const GLuint *baseInstances,
2916 GLsizei drawcount)
2917 {
2918 return rx::MultiDrawArraysInstancedBaseInstanceGeneral(
2919 this, context, mode, firsts, counts, instanceCounts, baseInstances, drawcount);
2920 }
2921
multiDrawElementsInstancedBaseVertexBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,const GLsizei * instanceCounts,const GLint * baseVertices,const GLuint * baseInstances,GLsizei drawcount)2922 angle::Result ContextVk::multiDrawElementsInstancedBaseVertexBaseInstance(
2923 const gl::Context *context,
2924 gl::PrimitiveMode mode,
2925 const GLsizei *counts,
2926 gl::DrawElementsType type,
2927 const GLvoid *const *indices,
2928 const GLsizei *instanceCounts,
2929 const GLint *baseVertices,
2930 const GLuint *baseInstances,
2931 GLsizei drawcount)
2932 {
2933 return rx::MultiDrawElementsInstancedBaseVertexBaseInstanceGeneral(
2934 this, context, mode, counts, type, indices, instanceCounts, baseVertices, baseInstances,
2935 drawcount);
2936 }
2937
optimizeRenderPassForPresent(VkFramebuffer framebufferHandle)2938 void ContextVk::optimizeRenderPassForPresent(VkFramebuffer framebufferHandle)
2939 {
2940 if (!mRenderPassCommands->started())
2941 {
2942 return;
2943 }
2944
2945 if (framebufferHandle != mRenderPassCommands->getFramebufferHandle())
2946 {
2947 return;
2948 }
2949
2950 RenderTargetVk *color0RenderTarget = mDrawFramebuffer->getColorDrawRenderTarget(0);
2951 if (!color0RenderTarget)
2952 {
2953 return;
2954 }
2955
2956 // EGL1.5 spec: The contents of ancillary buffers are always undefined after calling
2957 // eglSwapBuffers
2958 RenderTargetVk *depthStencilRenderTarget = mDrawFramebuffer->getDepthStencilRenderTarget();
2959 if (depthStencilRenderTarget)
2960 {
2961 // Change depthstencil attachment storeOp to DONT_CARE
2962 const gl::DepthStencilState &dsState = mState.getDepthStencilState();
2963 mRenderPassCommands->invalidateRenderPassStencilAttachment(
2964 dsState, mRenderPassCommands->getRenderArea());
2965 mRenderPassCommands->invalidateRenderPassDepthAttachment(
2966 dsState, mRenderPassCommands->getRenderArea());
2967 // Mark content as invalid so that we will not load them in next renderpass
2968 depthStencilRenderTarget->invalidateEntireContent(this);
2969 depthStencilRenderTarget->invalidateEntireStencilContent(this);
2970 }
2971
2972 // Use finalLayout instead of extra barrier for layout change to present
2973 vk::ImageHelper &image = color0RenderTarget->getImageForWrite();
2974 mRenderPassCommands->setImageOptimizeForPresent(&image);
2975 }
2976
getResetStatus()2977 gl::GraphicsResetStatus ContextVk::getResetStatus()
2978 {
2979 if (mRenderer->isDeviceLost())
2980 {
2981 // TODO(geofflang): It may be possible to track which context caused the device lost and
2982 // return either GL_GUILTY_CONTEXT_RESET or GL_INNOCENT_CONTEXT_RESET.
2983 // http://anglebug.com/2787
2984 return gl::GraphicsResetStatus::UnknownContextReset;
2985 }
2986
2987 return gl::GraphicsResetStatus::NoError;
2988 }
2989
insertEventMarker(GLsizei length,const char * marker)2990 angle::Result ContextVk::insertEventMarker(GLsizei length, const char *marker)
2991 {
2992 if (!mRenderer->enableDebugUtils() && !mRenderer->angleDebuggerMode())
2993 {
2994 return angle::Result::Continue;
2995 }
2996
2997 VkDebugUtilsLabelEXT label;
2998 vk::MakeDebugUtilsLabel(GL_DEBUG_SOURCE_APPLICATION, marker, &label);
2999 mOutsideRenderPassCommands->getCommandBuffer().insertDebugUtilsLabelEXT(label);
3000
3001 return angle::Result::Continue;
3002 }
3003
pushGroupMarker(GLsizei length,const char * marker)3004 angle::Result ContextVk::pushGroupMarker(GLsizei length, const char *marker)
3005 {
3006 if (!mRenderer->enableDebugUtils() && !mRenderer->angleDebuggerMode())
3007 {
3008 return angle::Result::Continue;
3009 }
3010
3011 VkDebugUtilsLabelEXT label;
3012 vk::MakeDebugUtilsLabel(GL_DEBUG_SOURCE_APPLICATION, marker, &label);
3013 mOutsideRenderPassCommands->getCommandBuffer().beginDebugUtilsLabelEXT(label);
3014
3015 return angle::Result::Continue;
3016 }
3017
popGroupMarker()3018 angle::Result ContextVk::popGroupMarker()
3019 {
3020 if (!mRenderer->enableDebugUtils() && !mRenderer->angleDebuggerMode())
3021 {
3022 return angle::Result::Continue;
3023 }
3024
3025 mOutsideRenderPassCommands->getCommandBuffer().endDebugUtilsLabelEXT();
3026
3027 return angle::Result::Continue;
3028 }
3029
pushDebugGroup(const gl::Context * context,GLenum source,GLuint id,const std::string & message)3030 angle::Result ContextVk::pushDebugGroup(const gl::Context *context,
3031 GLenum source,
3032 GLuint id,
3033 const std::string &message)
3034 {
3035 if (!mRenderer->enableDebugUtils() && !mRenderer->angleDebuggerMode())
3036 {
3037 return angle::Result::Continue;
3038 }
3039
3040 VkDebugUtilsLabelEXT label;
3041 vk::MakeDebugUtilsLabel(source, message.c_str(), &label);
3042 mOutsideRenderPassCommands->getCommandBuffer().beginDebugUtilsLabelEXT(label);
3043
3044 return angle::Result::Continue;
3045 }
3046
popDebugGroup(const gl::Context * context)3047 angle::Result ContextVk::popDebugGroup(const gl::Context *context)
3048 {
3049 if (!mRenderer->enableDebugUtils() && !mRenderer->angleDebuggerMode())
3050 {
3051 return angle::Result::Continue;
3052 }
3053
3054 mOutsideRenderPassCommands->getCommandBuffer().endDebugUtilsLabelEXT();
3055
3056 return angle::Result::Continue;
3057 }
3058
logEvent(const char * eventString)3059 void ContextVk::logEvent(const char *eventString)
3060 {
3061 if (!mRenderer->angleDebuggerMode())
3062 {
3063 return;
3064 }
3065
3066 // Save this event (about an OpenGL ES command being called).
3067 mEventLog.push_back(eventString);
3068
3069 // Set a dirty bit in order to stay off the "hot path" for when not logging.
3070 mGraphicsDirtyBits.set(DIRTY_BIT_EVENT_LOG);
3071 mComputeDirtyBits.set(DIRTY_BIT_EVENT_LOG);
3072 }
3073
endEventLog(angle::EntryPoint entryPoint,PipelineType pipelineType)3074 void ContextVk::endEventLog(angle::EntryPoint entryPoint, PipelineType pipelineType)
3075 {
3076 if (!mRenderer->angleDebuggerMode())
3077 {
3078 return;
3079 }
3080
3081 if (pipelineType == PipelineType::Graphics)
3082 {
3083 ASSERT(mRenderPassCommands);
3084 mRenderPassCommands->getCommandBuffer().endDebugUtilsLabelEXT();
3085 }
3086 else
3087 {
3088 ASSERT(pipelineType == PipelineType::Compute);
3089 ASSERT(mOutsideRenderPassCommands);
3090 mOutsideRenderPassCommands->getCommandBuffer().endDebugUtilsLabelEXT();
3091 }
3092 }
endEventLogForClearOrQuery()3093 void ContextVk::endEventLogForClearOrQuery()
3094 {
3095 if (!mRenderer->angleDebuggerMode())
3096 {
3097 return;
3098 }
3099
3100 vk::CommandBuffer *commandBuffer = nullptr;
3101 switch (mQueryEventType)
3102 {
3103 case GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd:
3104 ASSERT(mOutsideRenderPassCommands);
3105 commandBuffer = &mOutsideRenderPassCommands->getCommandBuffer();
3106 break;
3107 case GraphicsEventCmdBuf::InRenderPassCmdBufQueryCmd:
3108 ASSERT(mRenderPassCommands);
3109 commandBuffer = &mRenderPassCommands->getCommandBuffer();
3110 break;
3111 case GraphicsEventCmdBuf::NotInQueryCmd:
3112 // The glClear* or gl*Query* command was noop'd or otherwise ended early. We could
3113 // call handleDirtyEventLogImpl() to start the hierarchy, but it isn't clear which (if
3114 // any) command buffer to use. We'll just skip processing this command (other than to
3115 // let it stay queued for the next time handleDirtyEventLogImpl() is called.
3116 return;
3117 default:
3118 UNREACHABLE();
3119 }
3120 commandBuffer->endDebugUtilsLabelEXT();
3121
3122 mQueryEventType = GraphicsEventCmdBuf::NotInQueryCmd;
3123 }
3124
handleNoopDrawEvent()3125 angle::Result ContextVk::handleNoopDrawEvent()
3126 {
3127 // Even though this draw call is being no-op'd, we still must handle the dirty event log
3128 return handleDirtyEventLogImpl(mRenderPassCommandBuffer);
3129 }
3130
handleGraphicsEventLog(GraphicsEventCmdBuf queryEventType)3131 angle::Result ContextVk::handleGraphicsEventLog(GraphicsEventCmdBuf queryEventType)
3132 {
3133 ASSERT(mQueryEventType == GraphicsEventCmdBuf::NotInQueryCmd);
3134 if (!mRenderer->angleDebuggerMode())
3135 {
3136 return angle::Result::Continue;
3137 }
3138
3139 mQueryEventType = queryEventType;
3140
3141 vk::CommandBuffer *commandBuffer = nullptr;
3142 switch (mQueryEventType)
3143 {
3144 case GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd:
3145 ASSERT(mOutsideRenderPassCommands);
3146 commandBuffer = &mOutsideRenderPassCommands->getCommandBuffer();
3147 break;
3148 case GraphicsEventCmdBuf::InRenderPassCmdBufQueryCmd:
3149 ASSERT(mRenderPassCommands);
3150 commandBuffer = &mRenderPassCommands->getCommandBuffer();
3151 break;
3152 default:
3153 UNREACHABLE();
3154 }
3155 return handleDirtyEventLogImpl(commandBuffer);
3156 }
3157
isViewportFlipEnabledForDrawFBO() const3158 bool ContextVk::isViewportFlipEnabledForDrawFBO() const
3159 {
3160 return mFlipViewportForDrawFramebuffer && mFlipYForCurrentSurface;
3161 }
3162
isViewportFlipEnabledForReadFBO() const3163 bool ContextVk::isViewportFlipEnabledForReadFBO() const
3164 {
3165 return mFlipViewportForReadFramebuffer;
3166 }
3167
isRotatedAspectRatioForDrawFBO() const3168 bool ContextVk::isRotatedAspectRatioForDrawFBO() const
3169 {
3170 return IsRotatedAspectRatio(mCurrentRotationDrawFramebuffer);
3171 }
3172
isRotatedAspectRatioForReadFBO() const3173 bool ContextVk::isRotatedAspectRatioForReadFBO() const
3174 {
3175 return IsRotatedAspectRatio(mCurrentRotationReadFramebuffer);
3176 }
3177
getRotationDrawFramebuffer() const3178 SurfaceRotation ContextVk::getRotationDrawFramebuffer() const
3179 {
3180 return mCurrentRotationDrawFramebuffer;
3181 }
3182
getRotationReadFramebuffer() const3183 SurfaceRotation ContextVk::getRotationReadFramebuffer() const
3184 {
3185 return mCurrentRotationReadFramebuffer;
3186 }
3187
updateColorMasks(const gl::BlendStateExt & blendStateExt)3188 void ContextVk::updateColorMasks(const gl::BlendStateExt &blendStateExt)
3189 {
3190 mClearColorMasks = blendStateExt.mColorMask;
3191
3192 FramebufferVk *framebufferVk = vk::GetImpl(mState.getDrawFramebuffer());
3193 mGraphicsPipelineDesc->updateColorWriteMasks(&mGraphicsPipelineTransition, mClearColorMasks,
3194 framebufferVk->getEmulatedAlphaAttachmentMask(),
3195 framebufferVk->getState().getEnabledDrawBuffers());
3196 }
3197
updateSampleMaskWithRasterizationSamples(const uint32_t rasterizationSamples)3198 void ContextVk::updateSampleMaskWithRasterizationSamples(const uint32_t rasterizationSamples)
3199 {
3200 // FramebufferVk::syncState could have been the origin for this call, at which point the
3201 // draw FBO may have changed, retrieve the latest draw FBO.
3202 FramebufferVk *drawFramebuffer = vk::GetImpl(mState.getDrawFramebuffer());
3203
3204 // If sample coverage is enabled, emulate it by generating and applying a mask on top of the
3205 // sample mask.
3206 uint32_t coverageSampleCount = GetCoverageSampleCount(mState, drawFramebuffer);
3207
3208 static_assert(sizeof(uint32_t) == sizeof(GLbitfield), "Vulkan assumes 32-bit sample masks");
3209 for (uint32_t maskNumber = 0; maskNumber < mState.getMaxSampleMaskWords(); ++maskNumber)
3210 {
3211 uint32_t mask = mState.isSampleMaskEnabled() && rasterizationSamples > 1
3212 ? mState.getSampleMaskWord(maskNumber)
3213 : std::numeric_limits<uint32_t>::max();
3214
3215 ApplySampleCoverage(mState, coverageSampleCount, maskNumber, &mask);
3216
3217 mGraphicsPipelineDesc->updateSampleMask(&mGraphicsPipelineTransition, maskNumber, mask);
3218 }
3219 }
3220
getCorrectedViewport(const gl::Rectangle & viewport) const3221 gl::Rectangle ContextVk::getCorrectedViewport(const gl::Rectangle &viewport) const
3222 {
3223 const gl::Caps &caps = getCaps();
3224 const VkPhysicalDeviceLimits &limitsVk = mRenderer->getPhysicalDeviceProperties().limits;
3225 const int viewportBoundsRangeLow = static_cast<int>(limitsVk.viewportBoundsRange[0]);
3226 const int viewportBoundsRangeHigh = static_cast<int>(limitsVk.viewportBoundsRange[1]);
3227
3228 // Clamp the viewport values to what Vulkan specifies
3229
3230 // width must be greater than 0.0 and less than or equal to
3231 // VkPhysicalDeviceLimits::maxViewportDimensions[0]
3232 int correctedWidth = std::min<int>(viewport.width, caps.maxViewportWidth);
3233 correctedWidth = std::max<int>(correctedWidth, 0);
3234 // height must be greater than 0.0 and less than or equal to
3235 // VkPhysicalDeviceLimits::maxViewportDimensions[1]
3236 int correctedHeight = std::min<int>(viewport.height, caps.maxViewportHeight);
3237 correctedHeight = std::max<int>(correctedHeight, 0);
3238 // x and y must each be between viewportBoundsRange[0] and viewportBoundsRange[1], inclusive.
3239 // Viewport size cannot be 0 so ensure there is always size for a 1x1 viewport
3240 int correctedX = std::min<int>(viewport.x, viewportBoundsRangeHigh - 1);
3241 correctedX = std::max<int>(correctedX, viewportBoundsRangeLow);
3242 int correctedY = std::min<int>(viewport.y, viewportBoundsRangeHigh - 1);
3243 correctedY = std::max<int>(correctedY, viewportBoundsRangeLow);
3244 // x + width must be less than or equal to viewportBoundsRange[1]
3245 if ((correctedX + correctedWidth) > viewportBoundsRangeHigh)
3246 {
3247 correctedWidth = viewportBoundsRangeHigh - correctedX;
3248 }
3249 // y + height must be less than or equal to viewportBoundsRange[1]
3250 if ((correctedY + correctedHeight) > viewportBoundsRangeHigh)
3251 {
3252 correctedHeight = viewportBoundsRangeHigh - correctedY;
3253 }
3254
3255 return gl::Rectangle(correctedX, correctedY, correctedWidth, correctedHeight);
3256 }
3257
updateViewport(FramebufferVk * framebufferVk,const gl::Rectangle & viewport,float nearPlane,float farPlane)3258 void ContextVk::updateViewport(FramebufferVk *framebufferVk,
3259 const gl::Rectangle &viewport,
3260 float nearPlane,
3261 float farPlane)
3262 {
3263
3264 gl::Box fbDimensions = framebufferVk->getState().getDimensions();
3265 gl::Rectangle correctedRect = getCorrectedViewport(viewport);
3266 gl::Rectangle rotatedRect;
3267 RotateRectangle(getRotationDrawFramebuffer(), false, fbDimensions.width, fbDimensions.height,
3268 correctedRect, &rotatedRect);
3269
3270 bool invertViewport =
3271 isViewportFlipEnabledForDrawFBO() && getFeatures().supportsNegativeViewport.enabled;
3272
3273 gl_vk::GetViewport(
3274 rotatedRect, nearPlane, farPlane, invertViewport,
3275 // If clip space origin is upper left, viewport origin's y value will be offset by the
3276 // height of the viewport when clip space is mapped into screen space.
3277 mState.getClipSpaceOrigin() == gl::ClipSpaceOrigin::UpperLeft,
3278 // If the surface is rotated 90/270 degrees, use the framebuffer's width instead of the
3279 // height for calculating the final viewport.
3280 isRotatedAspectRatioForDrawFBO() ? fbDimensions.width : fbDimensions.height, &mViewport);
3281
3282 // Ensure viewport is within Vulkan requirements
3283 vk::ClampViewport(&mViewport);
3284
3285 invalidateGraphicsDriverUniforms();
3286 mGraphicsDirtyBits.set(DIRTY_BIT_VIEWPORT);
3287 }
3288
updateDepthRange(float nearPlane,float farPlane)3289 void ContextVk::updateDepthRange(float nearPlane, float farPlane)
3290 {
3291 // GLES2.0 Section 2.12.1: Each of n and f are clamped to lie within [0, 1], as are all
3292 // arguments of type clampf.
3293 ASSERT(nearPlane >= 0.0f && nearPlane <= 1.0f);
3294 ASSERT(farPlane >= 0.0f && farPlane <= 1.0f);
3295 mViewport.minDepth = nearPlane;
3296 mViewport.maxDepth = farPlane;
3297
3298 invalidateGraphicsDriverUniforms();
3299 mGraphicsDirtyBits.set(DIRTY_BIT_VIEWPORT);
3300 }
3301
updateScissor(const gl::State & glState)3302 void ContextVk::updateScissor(const gl::State &glState)
3303 {
3304 FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer());
3305 gl::Rectangle renderArea = framebufferVk->getNonRotatedCompleteRenderArea();
3306
3307 // Clip the render area to the viewport.
3308 gl::Rectangle viewportClippedRenderArea;
3309 if (!gl::ClipRectangle(renderArea, getCorrectedViewport(glState.getViewport()),
3310 &viewportClippedRenderArea))
3311 {
3312 viewportClippedRenderArea = gl::Rectangle();
3313 }
3314
3315 gl::Rectangle scissoredArea = ClipRectToScissor(getState(), viewportClippedRenderArea, false);
3316 gl::Rectangle rotatedScissoredArea;
3317 RotateRectangle(getRotationDrawFramebuffer(), isViewportFlipEnabledForDrawFBO(),
3318 renderArea.width, renderArea.height, scissoredArea, &rotatedScissoredArea);
3319 mScissor = gl_vk::GetRect(rotatedScissoredArea);
3320 mGraphicsDirtyBits.set(DIRTY_BIT_SCISSOR);
3321
3322 // If the scissor has grown beyond the previous scissoredRenderArea, grow the render pass render
3323 // area. The only undesirable effect this may have is that if the render area does not cover a
3324 // previously invalidated area, that invalidate will have to be discarded.
3325 if (mRenderPassCommandBuffer &&
3326 !mRenderPassCommands->getRenderArea().encloses(rotatedScissoredArea))
3327 {
3328 ASSERT(mRenderPassCommands->started());
3329 mRenderPassCommands->growRenderArea(this, rotatedScissoredArea);
3330 }
3331 }
3332
updateDepthStencil(const gl::State & glState)3333 void ContextVk::updateDepthStencil(const gl::State &glState)
3334 {
3335 const gl::DepthStencilState depthStencilState = glState.getDepthStencilState();
3336
3337 gl::Framebuffer *drawFramebuffer = mState.getDrawFramebuffer();
3338 mGraphicsPipelineDesc->updateDepthTestEnabled(&mGraphicsPipelineTransition, depthStencilState,
3339 drawFramebuffer);
3340 mGraphicsPipelineDesc->updateDepthWriteEnabled(&mGraphicsPipelineTransition, depthStencilState,
3341 drawFramebuffer);
3342 mGraphicsPipelineDesc->updateStencilTestEnabled(&mGraphicsPipelineTransition, depthStencilState,
3343 drawFramebuffer);
3344 mGraphicsPipelineDesc->updateStencilFrontWriteMask(&mGraphicsPipelineTransition,
3345 depthStencilState, drawFramebuffer);
3346 mGraphicsPipelineDesc->updateStencilBackWriteMask(&mGraphicsPipelineTransition,
3347 depthStencilState, drawFramebuffer);
3348 }
3349
3350 // If the target is a single-sampled target, sampleShading should be disabled, to use Bresenham line
3351 // raterization feature.
updateSampleShadingWithRasterizationSamples(const uint32_t rasterizationSamples)3352 void ContextVk::updateSampleShadingWithRasterizationSamples(const uint32_t rasterizationSamples)
3353 {
3354 bool sampleShadingEnable =
3355 (rasterizationSamples <= 1 ? false : mState.isSampleShadingEnabled());
3356
3357 mGraphicsPipelineDesc->updateSampleShading(&mGraphicsPipelineTransition, sampleShadingEnable,
3358 mState.getMinSampleShading());
3359 }
3360
3361 // If the target is switched between a single-sampled and multisample, the dependency related to the
3362 // rasterization sample should be updated.
updateRasterizationSamples(const uint32_t rasterizationSamples)3363 void ContextVk::updateRasterizationSamples(const uint32_t rasterizationSamples)
3364 {
3365 mGraphicsPipelineDesc->updateRasterizationSamples(&mGraphicsPipelineTransition,
3366 rasterizationSamples);
3367 updateSampleShadingWithRasterizationSamples(rasterizationSamples);
3368 updateSampleMaskWithRasterizationSamples(rasterizationSamples);
3369 }
3370
updateRasterizerDiscardEnabled(bool isPrimitivesGeneratedQueryActive)3371 void ContextVk::updateRasterizerDiscardEnabled(bool isPrimitivesGeneratedQueryActive)
3372 {
3373 // On some devices, when rasterizerDiscardEnable is enabled, the
3374 // VK_EXT_primitives_generated_query as well as the pipeline statistics query used to emulate it
3375 // are non-functional. For VK_EXT_primitives_generated_query there's a feature bit but not for
3376 // pipeline statistics query. If the primitives generated query is active (and rasterizer
3377 // discard is not supported), rasterizerDiscardEnable is set to false and the functionality
3378 // is otherwise emulated (by using an empty scissor).
3379
3380 // If the primitives generated query implementation supports rasterizer discard, just set
3381 // rasterizer discard as requested. Otherwise disable it.
3382 bool isRasterizerDiscardEnabled = mState.isRasterizerDiscardEnabled();
3383 bool isEmulatingRasterizerDiscard = isEmulatingRasterizerDiscardDuringPrimitivesGeneratedQuery(
3384 isPrimitivesGeneratedQueryActive);
3385
3386 mGraphicsPipelineDesc->updateRasterizerDiscardEnabled(
3387 &mGraphicsPipelineTransition, isRasterizerDiscardEnabled && !isEmulatingRasterizerDiscard);
3388
3389 invalidateCurrentGraphicsPipeline();
3390
3391 if (!isEmulatingRasterizerDiscard)
3392 {
3393 return;
3394 }
3395
3396 // If we are emulating rasterizer discard, update the scissor if in render pass. If not in
3397 // render pass, DIRTY_BIT_SCISSOR will be set when the render pass next starts.
3398 if (hasStartedRenderPass())
3399 {
3400 handleDirtyGraphicsScissorImpl(isPrimitivesGeneratedQueryActive);
3401 }
3402 }
3403
invalidateProgramBindingHelper(const gl::State & glState)3404 void ContextVk::invalidateProgramBindingHelper(const gl::State &glState)
3405 {
3406 mProgram = nullptr;
3407 mProgramPipeline = nullptr;
3408 mExecutable = nullptr;
3409
3410 if (glState.getProgram())
3411 {
3412 mProgram = vk::GetImpl(glState.getProgram());
3413 mExecutable = &mProgram->getExecutable();
3414 }
3415
3416 if (glState.getProgramPipeline())
3417 {
3418 mProgramPipeline = vk::GetImpl(glState.getProgramPipeline());
3419 if (!mExecutable)
3420 {
3421 // A bound program always overrides a program pipeline
3422 mExecutable = &mProgramPipeline->getExecutable();
3423 }
3424 }
3425
3426 if (mProgram)
3427 {
3428 mProgram->onProgramBind();
3429 }
3430 else if (mProgramPipeline)
3431 {
3432 mProgramPipeline->onProgramBind(this);
3433 }
3434 }
3435
invalidateProgramExecutableHelper(const gl::Context * context)3436 angle::Result ContextVk::invalidateProgramExecutableHelper(const gl::Context *context)
3437 {
3438 const gl::State &glState = context->getState();
3439 const gl::ProgramExecutable *executable = glState.getProgramExecutable();
3440
3441 if (glState.getProgramExecutable()->isCompute())
3442 {
3443 invalidateCurrentComputePipeline();
3444 }
3445 else
3446 {
3447 invalidateCurrentGraphicsPipeline();
3448 // No additional work is needed here. We will update the pipeline desc
3449 // later.
3450 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask());
3451 invalidateVertexAndIndexBuffers();
3452 bool useVertexBuffer = (executable->getMaxActiveAttribLocation() > 0);
3453 mNonIndexedDirtyBitsMask.set(DIRTY_BIT_VERTEX_BUFFERS, useVertexBuffer);
3454 mIndexedDirtyBitsMask.set(DIRTY_BIT_VERTEX_BUFFERS, useVertexBuffer);
3455 mCurrentGraphicsPipeline = nullptr;
3456 mGraphicsPipelineTransition.reset();
3457
3458 ASSERT(mExecutable);
3459 mExecutable->updateEarlyFragmentTestsOptimization(this);
3460
3461 if (mLastProgramUsesFramebufferFetch != executable->usesFramebufferFetch())
3462 {
3463 mLastProgramUsesFramebufferFetch = executable->usesFramebufferFetch();
3464 ANGLE_TRY(flushCommandsAndEndRenderPass());
3465
3466 ASSERT(mDrawFramebuffer);
3467 mDrawFramebuffer->onSwitchProgramFramebufferFetch(this,
3468 executable->usesFramebufferFetch());
3469 }
3470 }
3471
3472 return angle::Result::Continue;
3473 }
3474
syncState(const gl::Context * context,const gl::State::DirtyBits & dirtyBits,const gl::State::DirtyBits & bitMask)3475 angle::Result ContextVk::syncState(const gl::Context *context,
3476 const gl::State::DirtyBits &dirtyBits,
3477 const gl::State::DirtyBits &bitMask)
3478 {
3479 const gl::State &glState = context->getState();
3480 const gl::ProgramExecutable *programExecutable = glState.getProgramExecutable();
3481
3482 if ((dirtyBits & mPipelineDirtyBitsMask).any() &&
3483 (programExecutable == nullptr || !programExecutable->isCompute()))
3484 {
3485 invalidateCurrentGraphicsPipeline();
3486 }
3487
3488 for (auto iter = dirtyBits.begin(), endIter = dirtyBits.end(); iter != endIter; ++iter)
3489 {
3490 size_t dirtyBit = *iter;
3491 switch (dirtyBit)
3492 {
3493 case gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED:
3494 case gl::State::DIRTY_BIT_SCISSOR:
3495 updateScissor(glState);
3496 break;
3497 case gl::State::DIRTY_BIT_VIEWPORT:
3498 {
3499 FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer());
3500 updateViewport(framebufferVk, glState.getViewport(), glState.getNearPlane(),
3501 glState.getFarPlane());
3502 // Update the scissor, which will be constrained to the viewport
3503 updateScissor(glState);
3504 break;
3505 }
3506 case gl::State::DIRTY_BIT_DEPTH_RANGE:
3507 updateDepthRange(glState.getNearPlane(), glState.getFarPlane());
3508 break;
3509 case gl::State::DIRTY_BIT_BLEND_ENABLED:
3510 mGraphicsPipelineDesc->updateBlendEnabled(&mGraphicsPipelineTransition,
3511 glState.getBlendStateExt().mEnabledMask);
3512 break;
3513 case gl::State::DIRTY_BIT_BLEND_COLOR:
3514 mGraphicsPipelineDesc->updateBlendColor(&mGraphicsPipelineTransition,
3515 glState.getBlendColor());
3516 break;
3517 case gl::State::DIRTY_BIT_BLEND_FUNCS:
3518 mGraphicsPipelineDesc->updateBlendFuncs(&mGraphicsPipelineTransition,
3519 glState.getBlendStateExt());
3520 break;
3521 case gl::State::DIRTY_BIT_BLEND_EQUATIONS:
3522 mGraphicsPipelineDesc->updateBlendEquations(&mGraphicsPipelineTransition,
3523 glState.getBlendStateExt());
3524 break;
3525 case gl::State::DIRTY_BIT_COLOR_MASK:
3526 updateColorMasks(glState.getBlendStateExt());
3527 break;
3528 case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
3529 mGraphicsPipelineDesc->updateAlphaToCoverageEnable(
3530 &mGraphicsPipelineTransition, glState.isSampleAlphaToCoverageEnabled());
3531 static_assert(gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE >
3532 gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED,
3533 "Dirty bit order");
3534 iter.setLaterBit(gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE);
3535 break;
3536 case gl::State::DIRTY_BIT_SAMPLE_COVERAGE_ENABLED:
3537 updateSampleMaskWithRasterizationSamples(mDrawFramebuffer->getSamples());
3538 break;
3539 case gl::State::DIRTY_BIT_SAMPLE_COVERAGE:
3540 updateSampleMaskWithRasterizationSamples(mDrawFramebuffer->getSamples());
3541 break;
3542 case gl::State::DIRTY_BIT_SAMPLE_MASK_ENABLED:
3543 updateSampleMaskWithRasterizationSamples(mDrawFramebuffer->getSamples());
3544 break;
3545 case gl::State::DIRTY_BIT_SAMPLE_MASK:
3546 updateSampleMaskWithRasterizationSamples(mDrawFramebuffer->getSamples());
3547 break;
3548 case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED:
3549 {
3550 mGraphicsPipelineDesc->updateDepthTestEnabled(&mGraphicsPipelineTransition,
3551 glState.getDepthStencilState(),
3552 glState.getDrawFramebuffer());
3553 ANGLE_TRY(updateRenderPassDepthStencilAccess());
3554 break;
3555 }
3556 case gl::State::DIRTY_BIT_DEPTH_FUNC:
3557 mGraphicsPipelineDesc->updateDepthFunc(&mGraphicsPipelineTransition,
3558 glState.getDepthStencilState());
3559 break;
3560 case gl::State::DIRTY_BIT_DEPTH_MASK:
3561 {
3562 mGraphicsPipelineDesc->updateDepthWriteEnabled(&mGraphicsPipelineTransition,
3563 glState.getDepthStencilState(),
3564 glState.getDrawFramebuffer());
3565 ANGLE_TRY(updateRenderPassDepthStencilAccess());
3566 break;
3567 }
3568 case gl::State::DIRTY_BIT_STENCIL_TEST_ENABLED:
3569 {
3570 mGraphicsPipelineDesc->updateStencilTestEnabled(&mGraphicsPipelineTransition,
3571 glState.getDepthStencilState(),
3572 glState.getDrawFramebuffer());
3573 ANGLE_TRY(updateRenderPassDepthStencilAccess());
3574 break;
3575 }
3576 case gl::State::DIRTY_BIT_STENCIL_FUNCS_FRONT:
3577 mGraphicsPipelineDesc->updateStencilFrontFuncs(&mGraphicsPipelineTransition,
3578 glState.getStencilRef(),
3579 glState.getDepthStencilState());
3580 break;
3581 case gl::State::DIRTY_BIT_STENCIL_FUNCS_BACK:
3582 mGraphicsPipelineDesc->updateStencilBackFuncs(&mGraphicsPipelineTransition,
3583 glState.getStencilBackRef(),
3584 glState.getDepthStencilState());
3585 break;
3586 case gl::State::DIRTY_BIT_STENCIL_OPS_FRONT:
3587 mGraphicsPipelineDesc->updateStencilFrontOps(&mGraphicsPipelineTransition,
3588 glState.getDepthStencilState());
3589 break;
3590 case gl::State::DIRTY_BIT_STENCIL_OPS_BACK:
3591 mGraphicsPipelineDesc->updateStencilBackOps(&mGraphicsPipelineTransition,
3592 glState.getDepthStencilState());
3593 break;
3594 case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT:
3595 mGraphicsPipelineDesc->updateStencilFrontWriteMask(&mGraphicsPipelineTransition,
3596 glState.getDepthStencilState(),
3597 glState.getDrawFramebuffer());
3598 break;
3599 case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK:
3600 mGraphicsPipelineDesc->updateStencilBackWriteMask(&mGraphicsPipelineTransition,
3601 glState.getDepthStencilState(),
3602 glState.getDrawFramebuffer());
3603 break;
3604 case gl::State::DIRTY_BIT_CULL_FACE_ENABLED:
3605 case gl::State::DIRTY_BIT_CULL_FACE:
3606 mGraphicsPipelineDesc->updateCullMode(&mGraphicsPipelineTransition,
3607 glState.getRasterizerState());
3608 break;
3609 case gl::State::DIRTY_BIT_FRONT_FACE:
3610 mGraphicsPipelineDesc->updateFrontFace(&mGraphicsPipelineTransition,
3611 glState.getRasterizerState(),
3612 isYFlipEnabledForDrawFBO());
3613 break;
3614 case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED:
3615 mGraphicsPipelineDesc->updatePolygonOffsetFillEnabled(
3616 &mGraphicsPipelineTransition, glState.isPolygonOffsetFillEnabled());
3617 break;
3618 case gl::State::DIRTY_BIT_POLYGON_OFFSET:
3619 mGraphicsPipelineDesc->updatePolygonOffset(&mGraphicsPipelineTransition,
3620 glState.getRasterizerState());
3621 break;
3622 case gl::State::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED:
3623 updateRasterizerDiscardEnabled(
3624 mState.isQueryActive(gl::QueryType::PrimitivesGenerated));
3625 break;
3626 case gl::State::DIRTY_BIT_LINE_WIDTH:
3627 mGraphicsPipelineDesc->updateLineWidth(&mGraphicsPipelineTransition,
3628 glState.getLineWidth());
3629 break;
3630 case gl::State::DIRTY_BIT_PRIMITIVE_RESTART_ENABLED:
3631 mGraphicsPipelineDesc->updatePrimitiveRestartEnabled(
3632 &mGraphicsPipelineTransition, glState.isPrimitiveRestartEnabled());
3633 break;
3634 case gl::State::DIRTY_BIT_CLEAR_COLOR:
3635 mClearColorValue.color.float32[0] = glState.getColorClearValue().red;
3636 mClearColorValue.color.float32[1] = glState.getColorClearValue().green;
3637 mClearColorValue.color.float32[2] = glState.getColorClearValue().blue;
3638 mClearColorValue.color.float32[3] = glState.getColorClearValue().alpha;
3639 break;
3640 case gl::State::DIRTY_BIT_CLEAR_DEPTH:
3641 mClearDepthStencilValue.depthStencil.depth = glState.getDepthClearValue();
3642 break;
3643 case gl::State::DIRTY_BIT_CLEAR_STENCIL:
3644 mClearDepthStencilValue.depthStencil.stencil =
3645 static_cast<uint32_t>(glState.getStencilClearValue());
3646 break;
3647 case gl::State::DIRTY_BIT_UNPACK_STATE:
3648 // This is a no-op, it's only important to use the right unpack state when we do
3649 // setImage or setSubImage in TextureVk, which is plumbed through the frontend
3650 // call
3651 break;
3652 case gl::State::DIRTY_BIT_UNPACK_BUFFER_BINDING:
3653 break;
3654 case gl::State::DIRTY_BIT_PACK_STATE:
3655 // This is a no-op, its only important to use the right pack state when we do
3656 // call readPixels later on.
3657 break;
3658 case gl::State::DIRTY_BIT_PACK_BUFFER_BINDING:
3659 break;
3660 case gl::State::DIRTY_BIT_DITHER_ENABLED:
3661 break;
3662 case gl::State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING:
3663 updateFlipViewportReadFramebuffer(context->getState());
3664 updateSurfaceRotationReadFramebuffer(glState);
3665 break;
3666 case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING:
3667 {
3668 // FramebufferVk::syncState signals that we should start a new command buffer.
3669 // But changing the binding can skip FramebufferVk::syncState if the Framebuffer
3670 // has no dirty bits. Thus we need to explicitly clear the current command
3671 // buffer to ensure we start a new one. We don't actually close the render pass here
3672 // as some optimizations in non-draw commands require the render pass to remain
3673 // open, such as invalidate or blit. Note that we always start a new command buffer
3674 // because we currently can only support one open RenderPass at a time.
3675 onRenderPassFinished();
3676 if (mRenderer->getFeatures().preferSubmitAtFBOBoundary.enabled)
3677 {
3678 // This will behave as if user called glFlush, but the actual flush will be
3679 // triggered at endRenderPass time.
3680 mHasDeferredFlush = true;
3681 }
3682 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
3683 mDrawFramebuffer = vk::GetImpl(drawFramebuffer);
3684 mDrawFramebuffer->setReadOnlyDepthFeedbackLoopMode(false);
3685 updateFlipViewportDrawFramebuffer(glState);
3686 updateSurfaceRotationDrawFramebuffer(glState);
3687 SpecConstUsageBits usageBits = getCurrentProgramSpecConstUsageBits();
3688 updateGraphicsPipelineDescWithSpecConstUsageBits(usageBits);
3689 updateViewport(mDrawFramebuffer, glState.getViewport(), glState.getNearPlane(),
3690 glState.getFarPlane());
3691 updateColorMasks(glState.getBlendStateExt());
3692 updateRasterizationSamples(mDrawFramebuffer->getSamples());
3693 updateRasterizerDiscardEnabled(
3694 mState.isQueryActive(gl::QueryType::PrimitivesGenerated));
3695
3696 mGraphicsPipelineDesc->updateFrontFace(&mGraphicsPipelineTransition,
3697 glState.getRasterizerState(),
3698 isYFlipEnabledForDrawFBO());
3699 updateScissor(glState);
3700 updateDepthStencil(glState);
3701 mGraphicsPipelineDesc->resetSubpass(&mGraphicsPipelineTransition);
3702 onDrawFramebufferRenderPassDescChange(mDrawFramebuffer, nullptr);
3703 break;
3704 }
3705 case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING:
3706 break;
3707 case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING:
3708 {
3709 mVertexArray = vk::GetImpl(glState.getVertexArray());
3710 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask());
3711 ANGLE_TRY(mVertexArray->updateActiveAttribInfo(this));
3712 ANGLE_TRY(onIndexBufferChange(mVertexArray->getCurrentElementArrayBuffer()));
3713 break;
3714 }
3715 case gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING:
3716 break;
3717 case gl::State::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING:
3718 break;
3719 case gl::State::DIRTY_BIT_PROGRAM_BINDING:
3720 invalidateProgramBindingHelper(glState);
3721 break;
3722 case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
3723 {
3724 ASSERT(programExecutable);
3725 invalidateCurrentDefaultUniforms();
3726 static_assert(
3727 gl::State::DIRTY_BIT_TEXTURE_BINDINGS > gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE,
3728 "Dirty bit order");
3729 iter.setLaterBit(gl::State::DIRTY_BIT_TEXTURE_BINDINGS);
3730 static_assert(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING >
3731 gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE,
3732 "Dirty bit order");
3733 iter.setLaterBit(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING);
3734 ANGLE_TRY(invalidateProgramExecutableHelper(context));
3735 break;
3736 }
3737 case gl::State::DIRTY_BIT_SAMPLER_BINDINGS:
3738 {
3739 static_assert(
3740 gl::State::DIRTY_BIT_TEXTURE_BINDINGS > gl::State::DIRTY_BIT_SAMPLER_BINDINGS,
3741 "Dirty bit order");
3742 iter.setLaterBit(gl::State::DIRTY_BIT_TEXTURE_BINDINGS);
3743 break;
3744 }
3745 case gl::State::DIRTY_BIT_TEXTURE_BINDINGS:
3746 ANGLE_TRY(invalidateCurrentTextures(context));
3747 break;
3748 case gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING:
3749 // Nothing to do.
3750 break;
3751 case gl::State::DIRTY_BIT_IMAGE_BINDINGS:
3752 static_assert(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING >
3753 gl::State::DIRTY_BIT_IMAGE_BINDINGS,
3754 "Dirty bit order");
3755 iter.setLaterBit(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING);
3756 break;
3757 case gl::State::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING:
3758 static_assert(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING >
3759 gl::State::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING,
3760 "Dirty bit order");
3761 iter.setLaterBit(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING);
3762 break;
3763 case gl::State::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS:
3764 static_assert(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING >
3765 gl::State::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS,
3766 "Dirty bit order");
3767 iter.setLaterBit(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING);
3768 break;
3769 case gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING:
3770 ANGLE_TRY(invalidateCurrentShaderResources());
3771 invalidateDriverUniforms();
3772 break;
3773 case gl::State::DIRTY_BIT_MULTISAMPLING:
3774 // TODO(syoussefi): this should configure the pipeline to render as if
3775 // single-sampled, and write the results to all samples of a pixel regardless of
3776 // coverage. See EXT_multisample_compatibility. http://anglebug.com/3204
3777 break;
3778 case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_ONE:
3779 // TODO(syoussefi): this is part of EXT_multisample_compatibility. The
3780 // alphaToOne Vulkan feature should be enabled to support this extension.
3781 // http://anglebug.com/3204
3782 mGraphicsPipelineDesc->updateAlphaToOneEnable(&mGraphicsPipelineTransition,
3783 glState.isSampleAlphaToOneEnabled());
3784 break;
3785 case gl::State::DIRTY_BIT_SAMPLE_SHADING:
3786 updateSampleShadingWithRasterizationSamples(mDrawFramebuffer->getSamples());
3787 break;
3788 case gl::State::DIRTY_BIT_COVERAGE_MODULATION:
3789 break;
3790 case gl::State::DIRTY_BIT_FRAMEBUFFER_SRGB_WRITE_CONTROL_MODE:
3791 break;
3792 case gl::State::DIRTY_BIT_CURRENT_VALUES:
3793 {
3794 invalidateDefaultAttributes(glState.getAndResetDirtyCurrentValues());
3795 break;
3796 }
3797 case gl::State::DIRTY_BIT_PROVOKING_VERTEX:
3798 break;
3799 case gl::State::DIRTY_BIT_EXTENDED:
3800 {
3801 gl::State::ExtendedDirtyBits extendedDirtyBits =
3802 glState.getAndResetExtendedDirtyBits();
3803 for (size_t extendedDirtyBit : extendedDirtyBits)
3804 {
3805 switch (extendedDirtyBit)
3806 {
3807 case gl::State::ExtendedDirtyBitType::EXTENDED_DIRTY_BIT_CLIP_CONTROL:
3808 updateViewport(vk::GetImpl(glState.getDrawFramebuffer()),
3809 glState.getViewport(), glState.getNearPlane(),
3810 glState.getFarPlane());
3811 // Since we are flipping the y coordinate, update front face state
3812 mGraphicsPipelineDesc->updateFrontFace(&mGraphicsPipelineTransition,
3813 glState.getRasterizerState(),
3814 isYFlipEnabledForDrawFBO());
3815 updateScissor(glState);
3816
3817 // Nothing is needed for depth correction for EXT_clip_control.
3818 // glState will be used to toggle control path of depth correction code
3819 // in SPIR-V tranform options.
3820 break;
3821 case gl::State::ExtendedDirtyBitType::EXTENDED_DIRTY_BIT_CLIP_DISTANCES:
3822 invalidateGraphicsDriverUniforms();
3823 break;
3824 case gl::State::ExtendedDirtyBitType::
3825 EXTENDED_DIRTY_BIT_MIPMAP_GENERATION_HINT:
3826 break;
3827 case gl::State::ExtendedDirtyBitType::
3828 EXTENDED_DIRTY_BIT_SHADER_DERIVATIVE_HINT:
3829 break;
3830 default:
3831 UNREACHABLE();
3832 }
3833 }
3834 break;
3835 }
3836 case gl::State::DIRTY_BIT_PATCH_VERTICES:
3837 mGraphicsPipelineDesc->updatePatchVertices(&mGraphicsPipelineTransition,
3838 glState.getPatchVertices());
3839 break;
3840 default:
3841 UNREACHABLE();
3842 break;
3843 }
3844 }
3845
3846 return angle::Result::Continue;
3847 }
3848
getGPUDisjoint()3849 GLint ContextVk::getGPUDisjoint()
3850 {
3851 // No extension seems to be available to query this information.
3852 return 0;
3853 }
3854
getTimestamp()3855 GLint64 ContextVk::getTimestamp()
3856 {
3857 // This function should only be called if timestamp queries are available.
3858 ASSERT(mRenderer->getQueueFamilyProperties().timestampValidBits > 0);
3859
3860 uint64_t timestamp = 0;
3861
3862 (void)getTimestamp(×tamp);
3863
3864 return static_cast<GLint64>(timestamp);
3865 }
3866
onMakeCurrent(const gl::Context * context)3867 angle::Result ContextVk::onMakeCurrent(const gl::Context *context)
3868 {
3869 mRenderer->reloadVolkIfNeeded();
3870
3871 // Flip viewports if the user did not request that the surface is flipped.
3872 egl::Surface *drawSurface = context->getCurrentDrawSurface();
3873 mFlipYForCurrentSurface =
3874 drawSurface != nullptr &&
3875 !IsMaskFlagSet(drawSurface->getOrientation(), EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE);
3876
3877 if (drawSurface && drawSurface->getType() == EGL_WINDOW_BIT)
3878 {
3879 mCurrentWindowSurface = GetImplAs<WindowSurfaceVk>(drawSurface);
3880 }
3881 else
3882 {
3883 mCurrentWindowSurface = nullptr;
3884 }
3885
3886 const gl::State &glState = context->getState();
3887 updateFlipViewportDrawFramebuffer(glState);
3888 updateFlipViewportReadFramebuffer(glState);
3889 updateSurfaceRotationDrawFramebuffer(glState);
3890 updateSurfaceRotationReadFramebuffer(glState);
3891
3892 if (getFeatures().forceDriverUniformOverSpecConst.enabled)
3893 {
3894 invalidateDriverUniforms();
3895 }
3896 else
3897 {
3898 // Force update mGraphicsPipelineDesc
3899 mCurrentGraphicsPipeline = nullptr;
3900 invalidateCurrentGraphicsPipeline();
3901 }
3902
3903 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
3904 if (executable && executable->hasTransformFeedbackOutput() &&
3905 mState.isTransformFeedbackActive())
3906 {
3907 onTransformFeedbackStateChanged();
3908 if (getFeatures().supportsTransformFeedbackExtension.enabled)
3909 {
3910 mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME);
3911 }
3912 }
3913
3914 return angle::Result::Continue;
3915 }
3916
onUnMakeCurrent(const gl::Context * context)3917 angle::Result ContextVk::onUnMakeCurrent(const gl::Context *context)
3918 {
3919 ANGLE_TRY(flushImpl(nullptr));
3920 mCurrentWindowSurface = nullptr;
3921 return angle::Result::Continue;
3922 }
3923
updateFlipViewportDrawFramebuffer(const gl::State & glState)3924 void ContextVk::updateFlipViewportDrawFramebuffer(const gl::State &glState)
3925 {
3926 // The default framebuffer (originating from the swapchain) is rendered upside-down due to the
3927 // difference in the coordinate systems of Vulkan and GLES. Rendering upside-down has the
3928 // effect that rendering is done the same way as OpenGL. The KHR_MAINTENANCE_1 extension is
3929 // subsequently enabled to allow negative viewports. We inverse rendering to the backbuffer by
3930 // reversing the height of the viewport and increasing Y by the height. So if the viewport was
3931 // (0, 0, width, height), it becomes (0, height, width, -height). Unfortunately, when we start
3932 // doing this, we also need to adjust a number of places since the rendering now happens
3933 // upside-down. Affected places so far:
3934 //
3935 // - readPixels
3936 // - copyTexImage
3937 // - framebuffer blit
3938 // - generating mipmaps
3939 // - Point sprites tests
3940 // - texStorage
3941 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
3942 mFlipViewportForDrawFramebuffer = drawFramebuffer->isDefault();
3943 }
3944
updateFlipViewportReadFramebuffer(const gl::State & glState)3945 void ContextVk::updateFlipViewportReadFramebuffer(const gl::State &glState)
3946 {
3947 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
3948 mFlipViewportForReadFramebuffer = readFramebuffer->isDefault();
3949 }
3950
getCurrentProgramSpecConstUsageBits() const3951 SpecConstUsageBits ContextVk::getCurrentProgramSpecConstUsageBits() const
3952 {
3953 SpecConstUsageBits usageBits;
3954 if (mState.getProgram())
3955 {
3956 usageBits = mState.getProgram()->getState().getSpecConstUsageBits();
3957 }
3958 else if (mState.getProgramPipeline())
3959 {
3960 usageBits = mState.getProgramPipeline()->getState().getSpecConstUsageBits();
3961 }
3962 return usageBits;
3963 }
3964
updateGraphicsPipelineDescWithSpecConstUsageBits(SpecConstUsageBits usageBits)3965 void ContextVk::updateGraphicsPipelineDescWithSpecConstUsageBits(SpecConstUsageBits usageBits)
3966 {
3967 SurfaceRotation rotationAndFlip = mCurrentRotationDrawFramebuffer;
3968 ASSERT(ToUnderlying(rotationAndFlip) < ToUnderlying(SurfaceRotation::FlippedIdentity));
3969 bool yFlipped =
3970 isViewportFlipEnabledForDrawFBO() && (usageBits.test(sh::vk::SpecConstUsage::YFlip) ||
3971 !getFeatures().supportsNegativeViewport.enabled);
3972
3973 // usageBits are only set when specialization constants are used. With gl_Position pre-rotation
3974 // handled by the SPIR-V transformer, we need to have this information even when the driver
3975 // uniform path is taken to pre-rotate everything else.
3976 const bool programUsesRotation = usageBits.test(sh::vk::SpecConstUsage::Rotation) ||
3977 getFeatures().forceDriverUniformOverSpecConst.enabled;
3978
3979 // If program is not using rotation at all, we force it to use the Identity or FlippedIdentity
3980 // slot to improve the program cache hit rate
3981 if (!programUsesRotation)
3982 {
3983 rotationAndFlip = yFlipped ? SurfaceRotation::FlippedIdentity : SurfaceRotation::Identity;
3984 }
3985 else if (yFlipped)
3986 {
3987 // DetermineSurfaceRotation() does not encode yflip information. Shader code uses
3988 // SurfaceRotation specialization constant to determine yflip as well. We add yflip
3989 // information to the SurfaceRotation here so the shader does yflip properly.
3990 rotationAndFlip = static_cast<SurfaceRotation>(
3991 ToUnderlying(SurfaceRotation::FlippedIdentity) + ToUnderlying(rotationAndFlip));
3992 }
3993 else
3994 {
3995 // If program is not using yflip, then we just use the non-flipped slot to increase the
3996 // chance of pipeline program cache hit even if drawable is yflipped.
3997 }
3998
3999 if (rotationAndFlip != mGraphicsPipelineDesc->getSurfaceRotation())
4000 {
4001 // surface rotation are specialization constants, which affects program compilation. When
4002 // rotation changes, we need to update GraphicsPipelineDesc so that the correct pipeline
4003 // program object will be retrieved.
4004 mGraphicsPipelineDesc->updateSurfaceRotation(&mGraphicsPipelineTransition, rotationAndFlip);
4005 }
4006
4007 if (usageBits.test(sh::vk::SpecConstUsage::DrawableSize))
4008 {
4009 const gl::Box &dimensions = getState().getDrawFramebuffer()->getDimensions();
4010 mGraphicsPipelineDesc->updateDrawableSize(&mGraphicsPipelineTransition, dimensions.width,
4011 dimensions.height);
4012 }
4013 else
4014 {
4015 // Always set specialization constant to 1x1 if it is not used so that pipeline program with
4016 // only drawable size difference will be able to be reused.
4017 mGraphicsPipelineDesc->updateDrawableSize(&mGraphicsPipelineTransition, 1, 1);
4018 }
4019 }
4020
updateSurfaceRotationDrawFramebuffer(const gl::State & glState)4021 void ContextVk::updateSurfaceRotationDrawFramebuffer(const gl::State &glState)
4022 {
4023 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
4024 mCurrentRotationDrawFramebuffer =
4025 DetermineSurfaceRotation(drawFramebuffer, mCurrentWindowSurface);
4026 }
4027
updateSurfaceRotationReadFramebuffer(const gl::State & glState)4028 void ContextVk::updateSurfaceRotationReadFramebuffer(const gl::State &glState)
4029 {
4030 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
4031 mCurrentRotationReadFramebuffer =
4032 DetermineSurfaceRotation(readFramebuffer, mCurrentWindowSurface);
4033 }
4034
getNativeCaps() const4035 gl::Caps ContextVk::getNativeCaps() const
4036 {
4037 return mRenderer->getNativeCaps();
4038 }
4039
getNativeTextureCaps() const4040 const gl::TextureCapsMap &ContextVk::getNativeTextureCaps() const
4041 {
4042 return mRenderer->getNativeTextureCaps();
4043 }
4044
getNativeExtensions() const4045 const gl::Extensions &ContextVk::getNativeExtensions() const
4046 {
4047 return mRenderer->getNativeExtensions();
4048 }
4049
getNativeLimitations() const4050 const gl::Limitations &ContextVk::getNativeLimitations() const
4051 {
4052 return mRenderer->getNativeLimitations();
4053 }
4054
createCompiler()4055 CompilerImpl *ContextVk::createCompiler()
4056 {
4057 return new CompilerVk();
4058 }
4059
createShader(const gl::ShaderState & state)4060 ShaderImpl *ContextVk::createShader(const gl::ShaderState &state)
4061 {
4062 return new ShaderVk(state);
4063 }
4064
createProgram(const gl::ProgramState & state)4065 ProgramImpl *ContextVk::createProgram(const gl::ProgramState &state)
4066 {
4067 return new ProgramVk(state);
4068 }
4069
createFramebuffer(const gl::FramebufferState & state)4070 FramebufferImpl *ContextVk::createFramebuffer(const gl::FramebufferState &state)
4071 {
4072 return FramebufferVk::CreateUserFBO(mRenderer, state);
4073 }
4074
createTexture(const gl::TextureState & state)4075 TextureImpl *ContextVk::createTexture(const gl::TextureState &state)
4076 {
4077 return new TextureVk(state, mRenderer);
4078 }
4079
createRenderbuffer(const gl::RenderbufferState & state)4080 RenderbufferImpl *ContextVk::createRenderbuffer(const gl::RenderbufferState &state)
4081 {
4082 return new RenderbufferVk(state);
4083 }
4084
createBuffer(const gl::BufferState & state)4085 BufferImpl *ContextVk::createBuffer(const gl::BufferState &state)
4086 {
4087 return new BufferVk(state);
4088 }
4089
createVertexArray(const gl::VertexArrayState & state)4090 VertexArrayImpl *ContextVk::createVertexArray(const gl::VertexArrayState &state)
4091 {
4092 return new VertexArrayVk(this, state);
4093 }
4094
createQuery(gl::QueryType type)4095 QueryImpl *ContextVk::createQuery(gl::QueryType type)
4096 {
4097 return new QueryVk(type);
4098 }
4099
createFenceNV()4100 FenceNVImpl *ContextVk::createFenceNV()
4101 {
4102 return new FenceNVVk();
4103 }
4104
createSync()4105 SyncImpl *ContextVk::createSync()
4106 {
4107 return new SyncVk();
4108 }
4109
createTransformFeedback(const gl::TransformFeedbackState & state)4110 TransformFeedbackImpl *ContextVk::createTransformFeedback(const gl::TransformFeedbackState &state)
4111 {
4112 return new TransformFeedbackVk(state);
4113 }
4114
createSampler(const gl::SamplerState & state)4115 SamplerImpl *ContextVk::createSampler(const gl::SamplerState &state)
4116 {
4117 return new SamplerVk(state);
4118 }
4119
createProgramPipeline(const gl::ProgramPipelineState & state)4120 ProgramPipelineImpl *ContextVk::createProgramPipeline(const gl::ProgramPipelineState &state)
4121 {
4122 return new ProgramPipelineVk(state);
4123 }
4124
createMemoryObject()4125 MemoryObjectImpl *ContextVk::createMemoryObject()
4126 {
4127 return new MemoryObjectVk();
4128 }
4129
createSemaphore()4130 SemaphoreImpl *ContextVk::createSemaphore()
4131 {
4132 return new SemaphoreVk();
4133 }
4134
createOverlay(const gl::OverlayState & state)4135 OverlayImpl *ContextVk::createOverlay(const gl::OverlayState &state)
4136 {
4137 return new OverlayVk(state);
4138 }
4139
invalidateCurrentDefaultUniforms()4140 void ContextVk::invalidateCurrentDefaultUniforms()
4141 {
4142 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
4143 ASSERT(executable);
4144
4145 if (executable->hasDefaultUniforms())
4146 {
4147 mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
4148 mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
4149 }
4150 }
4151
invalidateCurrentTextures(const gl::Context * context)4152 angle::Result ContextVk::invalidateCurrentTextures(const gl::Context *context)
4153 {
4154 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
4155 ASSERT(executable);
4156
4157 if (executable->hasTextures())
4158 {
4159 mGraphicsDirtyBits |= kTexturesAndDescSetDirtyBits;
4160 mComputeDirtyBits |= kTexturesAndDescSetDirtyBits;
4161
4162 ANGLE_TRY(updateActiveTextures(context));
4163
4164 // Take care of read-after-write hazards that require implicit synchronization.
4165 if (executable->isCompute())
4166 {
4167 ANGLE_TRY(endRenderPassIfComputeReadAfterAttachmentWrite());
4168 }
4169 }
4170
4171 return angle::Result::Continue;
4172 }
4173
invalidateCurrentShaderResources()4174 angle::Result ContextVk::invalidateCurrentShaderResources()
4175 {
4176 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
4177 ASSERT(executable);
4178
4179 const bool hasImages = executable->hasImages();
4180 const bool hasStorageBuffers =
4181 executable->hasStorageBuffers() || executable->hasAtomicCounterBuffers();
4182 const bool hasUniformBuffers = executable->hasUniformBuffers();
4183
4184 if (hasUniformBuffers || hasStorageBuffers || hasImages || executable->usesFramebufferFetch())
4185 {
4186 mGraphicsDirtyBits |= kResourcesAndDescSetDirtyBits;
4187 mComputeDirtyBits |= kResourcesAndDescSetDirtyBits;
4188 }
4189
4190 // Take care of read-after-write hazards that require implicit synchronization.
4191 if (hasUniformBuffers && executable->isCompute())
4192 {
4193 ANGLE_TRY(endRenderPassIfComputeReadAfterTransformFeedbackWrite());
4194 }
4195
4196 // If memory barrier has been issued but the command buffers haven't been flushed, make sure
4197 // they get a chance to do so if necessary on program and storage buffer/image binding change.
4198 const bool hasGLMemoryBarrierIssuedInCommandBuffers =
4199 mOutsideRenderPassCommands->hasGLMemoryBarrierIssued() ||
4200 mRenderPassCommands->hasGLMemoryBarrierIssued();
4201
4202 if ((hasStorageBuffers || hasImages) && hasGLMemoryBarrierIssuedInCommandBuffers)
4203 {
4204 mGraphicsDirtyBits.set(DIRTY_BIT_MEMORY_BARRIER);
4205 mComputeDirtyBits.set(DIRTY_BIT_MEMORY_BARRIER);
4206 }
4207
4208 if (hasUniformBuffers || hasStorageBuffers)
4209 {
4210 mShaderBuffersDescriptorDesc.reset();
4211
4212 ProgramExecutableVk *executableVk = nullptr;
4213 if (mState.getProgram())
4214 {
4215 ProgramVk *programVk = vk::GetImpl(mState.getProgram());
4216 executableVk = &programVk->getExecutable();
4217 }
4218 else
4219 {
4220 ASSERT(mState.getProgramPipeline());
4221 ProgramPipelineVk *pipelineVk = vk::GetImpl(mState.getProgramPipeline());
4222 executableVk = &pipelineVk->getExecutable();
4223 }
4224
4225 const gl::BufferVector &uniformBuffers = mState.getOffsetBindingPointerUniformBuffers();
4226 AppendBufferVectorToDesc(&mShaderBuffersDescriptorDesc, uniformBuffers,
4227 mState.getUniformBuffersMask(),
4228 !executableVk->usesDynamicUniformBufferDescriptors());
4229
4230 const gl::BufferVector &shaderStorageBuffers =
4231 mState.getOffsetBindingPointerShaderStorageBuffers();
4232 AppendBufferVectorToDesc(&mShaderBuffersDescriptorDesc, shaderStorageBuffers,
4233 mState.getShaderStorageBuffersMask(), true);
4234
4235 const gl::BufferVector &atomicCounterBuffers =
4236 mState.getOffsetBindingPointerAtomicCounterBuffers();
4237 AppendBufferVectorToDesc(&mShaderBuffersDescriptorDesc, atomicCounterBuffers,
4238 mState.getAtomicCounterBuffersMask(), true);
4239 }
4240
4241 return angle::Result::Continue;
4242 }
4243
invalidateGraphicsDriverUniforms()4244 void ContextVk::invalidateGraphicsDriverUniforms()
4245 {
4246 mGraphicsDirtyBits |= kDriverUniformsAndBindingDirtyBits;
4247 }
4248
invalidateDriverUniforms()4249 void ContextVk::invalidateDriverUniforms()
4250 {
4251 mGraphicsDirtyBits |= kDriverUniformsAndBindingDirtyBits;
4252 mComputeDirtyBits |= kDriverUniformsAndBindingDirtyBits;
4253 }
4254
onFramebufferChange(FramebufferVk * framebufferVk)4255 angle::Result ContextVk::onFramebufferChange(FramebufferVk *framebufferVk)
4256 {
4257 // This is called from FramebufferVk::syncState. Skip these updates if the framebuffer being
4258 // synced is the read framebuffer (which is not equal the draw framebuffer).
4259 if (framebufferVk != vk::GetImpl(mState.getDrawFramebuffer()))
4260 {
4261 return angle::Result::Continue;
4262 }
4263
4264 // Ensure that the pipeline description is updated.
4265 if (mGraphicsPipelineDesc->getRasterizationSamples() !=
4266 static_cast<uint32_t>(framebufferVk->getSamples()))
4267 {
4268 updateRasterizationSamples(framebufferVk->getSamples());
4269 }
4270
4271 // Update scissor.
4272 updateScissor(mState);
4273
4274 // Update depth and stencil.
4275 updateDepthStencil(mState);
4276
4277 if (mState.getProgramExecutable())
4278 {
4279 ANGLE_TRY(invalidateCurrentShaderResources());
4280 }
4281
4282 onDrawFramebufferRenderPassDescChange(framebufferVk, nullptr);
4283
4284 return angle::Result::Continue;
4285 }
4286
onDrawFramebufferRenderPassDescChange(FramebufferVk * framebufferVk,bool * renderPassDescChangedOut)4287 void ContextVk::onDrawFramebufferRenderPassDescChange(FramebufferVk *framebufferVk,
4288 bool *renderPassDescChangedOut)
4289 {
4290 mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition,
4291 framebufferVk->getRenderPassDesc());
4292 const gl::Box &dimensions = framebufferVk->getState().getDimensions();
4293 mGraphicsPipelineDesc->updateDrawableSize(&mGraphicsPipelineTransition, dimensions.width,
4294 dimensions.height);
4295
4296 if (renderPassDescChangedOut)
4297 {
4298 // If render pass desc has changed while processing the dirty bits, notify the caller.
4299 *renderPassDescChangedOut = true;
4300 }
4301 else
4302 {
4303 // Otherwise mark the pipeline as dirty.
4304 invalidateCurrentGraphicsPipeline();
4305 }
4306 }
4307
invalidateCurrentTransformFeedbackBuffers()4308 void ContextVk::invalidateCurrentTransformFeedbackBuffers()
4309 {
4310 if (getFeatures().supportsTransformFeedbackExtension.enabled)
4311 {
4312 mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
4313 }
4314 else if (getFeatures().emulateTransformFeedback.enabled)
4315 {
4316 mGraphicsDirtyBits |= kXfbBuffersAndDescSetDirtyBits;
4317 }
4318 }
4319
onTransformFeedbackStateChanged()4320 void ContextVk::onTransformFeedbackStateChanged()
4321 {
4322 if (getFeatures().supportsTransformFeedbackExtension.enabled)
4323 {
4324 mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
4325 }
4326 else if (getFeatures().emulateTransformFeedback.enabled)
4327 {
4328 invalidateGraphicsDriverUniforms();
4329 invalidateCurrentTransformFeedbackBuffers();
4330 }
4331 }
4332
onBeginTransformFeedback(size_t bufferCount,const gl::TransformFeedbackBuffersArray<vk::BufferHelper * > & buffers,const gl::TransformFeedbackBuffersArray<vk::BufferHelper> & counterBuffers)4333 angle::Result ContextVk::onBeginTransformFeedback(
4334 size_t bufferCount,
4335 const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &buffers,
4336 const gl::TransformFeedbackBuffersArray<vk::BufferHelper> &counterBuffers)
4337 {
4338 onTransformFeedbackStateChanged();
4339
4340 bool shouldEndRenderPass = false;
4341
4342 // If any of the buffers were previously used in the render pass, break the render pass as a
4343 // barrier is needed.
4344 for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
4345 {
4346 const vk::BufferHelper *buffer = buffers[bufferIndex];
4347 if (mRenderPassCommands->usesBuffer(*buffer))
4348 {
4349 shouldEndRenderPass = true;
4350 break;
4351 }
4352 }
4353
4354 if (getFeatures().supportsTransformFeedbackExtension.enabled)
4355 {
4356 // Break the render pass if the counter buffers are used too. Note that Vulkan requires a
4357 // barrier on the counter buffer between pause and resume, so it cannot be resumed in the
4358 // same render pass. Note additionally that we don't need to test all counters being used
4359 // in the render pass, as outside of the transform feedback object these buffers are
4360 // inaccessible and are therefore always used together.
4361 if (!shouldEndRenderPass && mRenderPassCommands->usesBuffer(counterBuffers[0]))
4362 {
4363 shouldEndRenderPass = true;
4364 }
4365
4366 mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME);
4367 }
4368
4369 if (shouldEndRenderPass)
4370 {
4371 ANGLE_TRY(flushCommandsAndEndRenderPass());
4372 }
4373
4374 populateTransformFeedbackBufferSet(bufferCount, buffers);
4375
4376 return angle::Result::Continue;
4377 }
4378
populateTransformFeedbackBufferSet(size_t bufferCount,const gl::TransformFeedbackBuffersArray<vk::BufferHelper * > & buffers)4379 void ContextVk::populateTransformFeedbackBufferSet(
4380 size_t bufferCount,
4381 const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &buffers)
4382 {
4383 for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
4384 {
4385 vk::BufferHelper *buffer = buffers[bufferIndex];
4386 if (!mCurrentTransformFeedbackBuffers.contains(buffer))
4387 {
4388 mCurrentTransformFeedbackBuffers.insert(buffer);
4389 }
4390 }
4391 }
4392
onEndTransformFeedback()4393 void ContextVk::onEndTransformFeedback()
4394 {
4395 if (getFeatures().supportsTransformFeedbackExtension.enabled)
4396 {
4397 if (mRenderPassCommands->isTransformFeedbackStarted())
4398 {
4399 mRenderPassCommands->endTransformFeedback();
4400 }
4401 }
4402 else if (getFeatures().emulateTransformFeedback.enabled)
4403 {
4404 onTransformFeedbackStateChanged();
4405 }
4406 }
4407
onPauseTransformFeedback()4408 angle::Result ContextVk::onPauseTransformFeedback()
4409 {
4410 if (getFeatures().supportsTransformFeedbackExtension.enabled)
4411 {
4412 // If transform feedback was already active on this render pass, break it. This
4413 // is for simplicity to avoid tracking multiple simultaneously active transform feedback
4414 // settings in the render pass.
4415 if (mRenderPassCommands->isTransformFeedbackActiveUnpaused())
4416 {
4417 return flushCommandsAndEndRenderPass();
4418 }
4419 }
4420 else if (getFeatures().emulateTransformFeedback.enabled)
4421 {
4422 invalidateCurrentTransformFeedbackBuffers();
4423 }
4424 return angle::Result::Continue;
4425 }
4426
invalidateGraphicsPipelineBinding()4427 void ContextVk::invalidateGraphicsPipelineBinding()
4428 {
4429 mGraphicsDirtyBits.set(DIRTY_BIT_PIPELINE_BINDING);
4430 }
4431
invalidateComputePipelineBinding()4432 void ContextVk::invalidateComputePipelineBinding()
4433 {
4434 mComputeDirtyBits.set(DIRTY_BIT_PIPELINE_BINDING);
4435 }
4436
invalidateGraphicsDescriptorSet(DescriptorSetIndex usedDescriptorSet)4437 void ContextVk::invalidateGraphicsDescriptorSet(DescriptorSetIndex usedDescriptorSet)
4438 {
4439 // UtilsVk currently only uses set 0
4440 ASSERT(usedDescriptorSet == DescriptorSetIndex::Internal);
4441 if (mDriverUniforms[PipelineType::Graphics].descriptorSet != VK_NULL_HANDLE)
4442 {
4443 mGraphicsDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING);
4444 }
4445 }
4446
invalidateComputeDescriptorSet(DescriptorSetIndex usedDescriptorSet)4447 void ContextVk::invalidateComputeDescriptorSet(DescriptorSetIndex usedDescriptorSet)
4448 {
4449 // UtilsVk currently only uses set 0
4450 ASSERT(usedDescriptorSet == DescriptorSetIndex::Internal);
4451 if (mDriverUniforms[PipelineType::Compute].descriptorSet != VK_NULL_HANDLE)
4452 {
4453 mComputeDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING);
4454 }
4455 }
4456
invalidateViewportAndScissor()4457 void ContextVk::invalidateViewportAndScissor()
4458 {
4459 mGraphicsDirtyBits.set(DIRTY_BIT_VIEWPORT);
4460 mGraphicsDirtyBits.set(DIRTY_BIT_SCISSOR);
4461 }
4462
dispatchCompute(const gl::Context * context,GLuint numGroupsX,GLuint numGroupsY,GLuint numGroupsZ)4463 angle::Result ContextVk::dispatchCompute(const gl::Context *context,
4464 GLuint numGroupsX,
4465 GLuint numGroupsY,
4466 GLuint numGroupsZ)
4467 {
4468 ANGLE_TRY(setupDispatch(context));
4469
4470 mOutsideRenderPassCommands->getCommandBuffer().dispatch(numGroupsX, numGroupsY, numGroupsZ);
4471
4472 return angle::Result::Continue;
4473 }
4474
dispatchComputeIndirect(const gl::Context * context,GLintptr indirect)4475 angle::Result ContextVk::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect)
4476 {
4477 gl::Buffer *glBuffer = getState().getTargetBuffer(gl::BufferBinding::DispatchIndirect);
4478 VkDeviceSize bufferOffset = 0;
4479 vk::BufferHelper &buffer = vk::GetImpl(glBuffer)->getBufferAndOffset(&bufferOffset);
4480
4481 // Break the render pass if the indirect buffer was previously used as the output from transform
4482 // feedback.
4483 if (mCurrentTransformFeedbackBuffers.contains(&buffer))
4484 {
4485 ANGLE_TRY(flushCommandsAndEndRenderPass());
4486 }
4487
4488 ANGLE_TRY(setupDispatch(context));
4489
4490 // Process indirect buffer after command buffer has started.
4491 mOutsideRenderPassCommands->bufferRead(this, VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
4492 vk::PipelineStage::DrawIndirect, &buffer);
4493
4494 mOutsideRenderPassCommands->getCommandBuffer().dispatchIndirect(buffer.getBuffer(),
4495 bufferOffset + indirect);
4496
4497 return angle::Result::Continue;
4498 }
4499
memoryBarrier(const gl::Context * context,GLbitfield barriers)4500 angle::Result ContextVk::memoryBarrier(const gl::Context *context, GLbitfield barriers)
4501 {
4502 // First, turn GL_ALL_BARRIER_BITS into a mask that has only the valid barriers set.
4503 constexpr GLbitfield kCoreBarrierBits =
4504 GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT | GL_ELEMENT_ARRAY_BARRIER_BIT | GL_UNIFORM_BARRIER_BIT |
4505 GL_TEXTURE_FETCH_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_COMMAND_BARRIER_BIT |
4506 GL_PIXEL_BUFFER_BARRIER_BIT | GL_TEXTURE_UPDATE_BARRIER_BIT | GL_BUFFER_UPDATE_BARRIER_BIT |
4507 GL_FRAMEBUFFER_BARRIER_BIT | GL_TRANSFORM_FEEDBACK_BARRIER_BIT |
4508 GL_ATOMIC_COUNTER_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT;
4509 constexpr GLbitfield kExtensionBarrierBits = GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT;
4510
4511 barriers &= kCoreBarrierBits | kExtensionBarrierBits;
4512
4513 // GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT specifies that a fence sync or glFinish must be used
4514 // after the barrier for the CPU to to see the shader writes. Since host-visible buffer writes
4515 // always issue a barrier automatically for the sake of glMapBuffer() (see
4516 // comment on |mIsAnyHostVisibleBufferWritten|), there's nothing to do for
4517 // GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT.
4518 barriers &= ~GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT;
4519
4520 // If no other barrier, early out.
4521 if (barriers == 0)
4522 {
4523 return angle::Result::Continue;
4524 }
4525
4526 // glMemoryBarrier for barrier bit X_BARRIER_BIT implies:
4527 //
4528 // - An execution+memory barrier: shader writes are made visible to subsequent X accesses
4529 //
4530 // Additionally, SHADER_IMAGE_ACCESS_BARRIER_BIT and SHADER_STORAGE_BARRIER_BIT imply:
4531 //
4532 // - An execution+memory barrier: all accesses are finished before image/buffer writes
4533 //
4534 // For the first barrier, we can simplify the implementation by assuming that prior writes are
4535 // expected to be used right after this barrier, so we can close the render pass or flush the
4536 // outside render pass commands right away if they have had any writes.
4537 //
4538 // It's noteworthy that some barrier bits affect draw/dispatch calls only, while others affect
4539 // other commands. For the latter, since storage buffer and images are not tracked in command
4540 // buffers, we can't rely on the command buffers being flushed in the usual way when recording
4541 // these commands (i.e. through |getOutsideRenderPassCommandBuffer()| and
4542 // |vk::CommandBufferAccess|). Conservatively flushing command buffers with any storage output
4543 // simplifies this use case. If this needs to be avoided in the future,
4544 // |getOutsideRenderPassCommandBuffer()| can be modified to flush the command buffers if they
4545 // have had any storage output.
4546 //
4547 // For the second barrier, we need to defer closing the render pass until there's a draw or
4548 // dispatch call that uses storage buffers or images that were previously used in the render
4549 // pass. This allows the render pass to remain open in scenarios such as this:
4550 //
4551 // - Draw using resource X
4552 // - glMemoryBarrier
4553 // - Draw/dispatch with storage buffer/image Y
4554 //
4555 // To achieve this, a dirty bit is added that breaks the render pass if any storage
4556 // buffer/images are used in it. Until the render pass breaks, changing the program or storage
4557 // buffer/image bindings should set this dirty bit again.
4558
4559 if (mRenderPassCommands->hasShaderStorageOutput())
4560 {
4561 // Break the render pass if necessary as future non-draw commands can't know if they should.
4562 ANGLE_TRY(flushCommandsAndEndRenderPass());
4563 }
4564 else if (mOutsideRenderPassCommands->hasShaderStorageOutput())
4565 {
4566 // Otherwise flush the outside render pass commands if necessary.
4567 ANGLE_TRY(flushOutsideRenderPassCommands());
4568 }
4569
4570 constexpr GLbitfield kWriteAfterAccessBarriers =
4571 GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT;
4572
4573 if ((barriers & kWriteAfterAccessBarriers) == 0)
4574 {
4575 return angle::Result::Continue;
4576 }
4577
4578 // Defer flushing the command buffers until a draw/dispatch with storage buffer/image is
4579 // encountered.
4580 mGraphicsDirtyBits.set(DIRTY_BIT_MEMORY_BARRIER);
4581 mComputeDirtyBits.set(DIRTY_BIT_MEMORY_BARRIER);
4582
4583 // Make sure memory barrier is issued for future usages of storage buffers and images even if
4584 // there's no binding change.
4585 mGraphicsDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES);
4586 mComputeDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES);
4587
4588 // Mark the command buffers as affected by glMemoryBarrier, so future program and storage
4589 // buffer/image binding changes can set DIRTY_BIT_MEMORY_BARRIER again.
4590 mOutsideRenderPassCommands->setGLMemoryBarrierIssued();
4591 mRenderPassCommands->setGLMemoryBarrierIssued();
4592
4593 return angle::Result::Continue;
4594 }
4595
memoryBarrierByRegion(const gl::Context * context,GLbitfield barriers)4596 angle::Result ContextVk::memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers)
4597 {
4598 // Note: memoryBarrierByRegion is expected to affect only the fragment pipeline, but is
4599 // otherwise similar to memoryBarrier in function.
4600 //
4601 // TODO: Optimize memoryBarrierByRegion by issuing an in-subpass pipeline barrier instead of
4602 // breaking the render pass. http://anglebug.com/5132
4603 return memoryBarrier(context, barriers);
4604 }
4605
framebufferFetchBarrier()4606 void ContextVk::framebufferFetchBarrier()
4607 {
4608 mGraphicsDirtyBits.set(DIRTY_BIT_FRAMEBUFFER_FETCH_BARRIER);
4609 }
4610
getQueryPool(gl::QueryType queryType)4611 vk::DynamicQueryPool *ContextVk::getQueryPool(gl::QueryType queryType)
4612 {
4613 ASSERT(queryType == gl::QueryType::AnySamples ||
4614 queryType == gl::QueryType::AnySamplesConservative ||
4615 queryType == gl::QueryType::PrimitivesGenerated ||
4616 queryType == gl::QueryType::TransformFeedbackPrimitivesWritten ||
4617 queryType == gl::QueryType::Timestamp || queryType == gl::QueryType::TimeElapsed);
4618
4619 // For PrimitivesGenerated queries:
4620 //
4621 // - If VK_EXT_primitives_generated_query is supported, use that.
4622 // TODO: http://anglebug.com/5430
4623 // - Otherwise, if pipelineStatisticsQuery is supported, use that,
4624 // - Otherwise, use the same pool as TransformFeedbackPrimitivesWritten and share the query as
4625 // the Vulkan transform feedback query produces both results. This option is non-conformant
4626 // as the primitives generated query will not be functional without transform feedback.
4627 //
4628 if (queryType == gl::QueryType::PrimitivesGenerated &&
4629 !getFeatures().supportsPipelineStatisticsQuery.enabled)
4630 {
4631 queryType = gl::QueryType::TransformFeedbackPrimitivesWritten;
4632 }
4633
4634 // Assert that timestamp extension is available if needed.
4635 ASSERT(queryType != gl::QueryType::Timestamp && queryType != gl::QueryType::TimeElapsed ||
4636 mRenderer->getQueueFamilyProperties().timestampValidBits > 0);
4637 ASSERT(mQueryPools[queryType].isValid());
4638 return &mQueryPools[queryType];
4639 }
4640
getClearColorValue() const4641 const VkClearValue &ContextVk::getClearColorValue() const
4642 {
4643 return mClearColorValue;
4644 }
4645
getClearDepthStencilValue() const4646 const VkClearValue &ContextVk::getClearDepthStencilValue() const
4647 {
4648 return mClearDepthStencilValue;
4649 }
4650
getClearColorMasks() const4651 gl::BlendStateExt::ColorMaskStorage::Type ContextVk::getClearColorMasks() const
4652 {
4653 return mClearColorMasks;
4654 }
4655
writeAtomicCounterBufferDriverUniformOffsets(uint32_t * offsetsOut,size_t offsetsSize)4656 void ContextVk::writeAtomicCounterBufferDriverUniformOffsets(uint32_t *offsetsOut,
4657 size_t offsetsSize)
4658 {
4659 const VkDeviceSize offsetAlignment =
4660 mRenderer->getPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
4661 size_t atomicCounterBufferCount = mState.getAtomicCounterBufferCount();
4662
4663 ASSERT(atomicCounterBufferCount <= offsetsSize * 4);
4664
4665 for (uint32_t bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
4666 {
4667 uint32_t offsetDiff = 0;
4668
4669 const gl::OffsetBindingPointer<gl::Buffer> *atomicCounterBuffer =
4670 &mState.getIndexedAtomicCounterBuffer(bufferIndex);
4671 if (atomicCounterBuffer->get())
4672 {
4673 VkDeviceSize offset = atomicCounterBuffer->getOffset();
4674 VkDeviceSize alignedOffset = (offset / offsetAlignment) * offsetAlignment;
4675
4676 // GL requires the atomic counter buffer offset to be aligned with uint.
4677 ASSERT((offset - alignedOffset) % sizeof(uint32_t) == 0);
4678 offsetDiff = static_cast<uint32_t>((offset - alignedOffset) / sizeof(uint32_t));
4679
4680 // We expect offsetDiff to fit in an 8-bit value. The maximum difference is
4681 // minStorageBufferOffsetAlignment / 4, where minStorageBufferOffsetAlignment
4682 // currently has a maximum value of 256 on any device.
4683 ASSERT(offsetDiff < (1 << 8));
4684 }
4685
4686 // The output array is already cleared prior to this call.
4687 ASSERT(bufferIndex % 4 != 0 || offsetsOut[bufferIndex / 4] == 0);
4688
4689 offsetsOut[bufferIndex / 4] |= static_cast<uint8_t>(offsetDiff) << ((bufferIndex % 4) * 8);
4690 }
4691 }
4692
pauseTransformFeedbackIfActiveUnpaused()4693 void ContextVk::pauseTransformFeedbackIfActiveUnpaused()
4694 {
4695 if (mRenderPassCommands->isTransformFeedbackActiveUnpaused())
4696 {
4697 ASSERT(getFeatures().supportsTransformFeedbackExtension.enabled);
4698 mRenderPassCommands->pauseTransformFeedback();
4699
4700 // Note that this function is called when render pass break is imminent
4701 // (flushCommandsAndEndRenderPass(), or UtilsVk::clearFramebuffer which will close the
4702 // render pass after the clear). This dirty bit allows transform feedback to resume
4703 // automatically on next render pass.
4704 mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME);
4705 }
4706 }
4707
handleDirtyGraphicsDriverUniforms(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)4708 angle::Result ContextVk::handleDirtyGraphicsDriverUniforms(DirtyBits::Iterator *dirtyBitsIterator,
4709 DirtyBits dirtyBitMask)
4710 {
4711 // Allocate a new region in the dynamic buffer.
4712 bool useGraphicsDriverUniformsExtended = getFeatures().forceDriverUniformOverSpecConst.enabled;
4713 uint8_t *ptr;
4714 bool newBuffer;
4715 GraphicsDriverUniforms *driverUniforms;
4716 size_t driverUniformSize;
4717
4718 if (useGraphicsDriverUniformsExtended)
4719 {
4720 driverUniformSize = sizeof(GraphicsDriverUniformsExtended);
4721 }
4722 else
4723 {
4724 driverUniformSize = sizeof(GraphicsDriverUniforms);
4725 }
4726
4727 ANGLE_TRY(allocateDriverUniforms(driverUniformSize, &mDriverUniforms[PipelineType::Graphics],
4728 &ptr, &newBuffer));
4729
4730 if (useGraphicsDriverUniformsExtended)
4731 {
4732 float halfRenderAreaWidth =
4733 static_cast<float>(mDrawFramebuffer->getState().getDimensions().width) * 0.5f;
4734 float halfRenderAreaHeight =
4735 static_cast<float>(mDrawFramebuffer->getState().getDimensions().height) * 0.5f;
4736
4737 float flipX = 1.0f;
4738 float flipY = -1.0f;
4739 // Y-axis flipping only comes into play with the default framebuffer (i.e. a swapchain
4740 // image). For 0-degree rotation, an FBO or pbuffer could be the draw framebuffer, and so we
4741 // must check whether flipY should be positive or negative. All other rotations, will be to
4742 // the default framebuffer, and so the value of isViewportFlipEnabledForDrawFBO() is assumed
4743 // true; the appropriate flipY value is chosen such that gl_FragCoord is positioned at the
4744 // lower-left corner of the window.
4745 switch (mCurrentRotationDrawFramebuffer)
4746 {
4747 case SurfaceRotation::Identity:
4748 flipX = 1.0f;
4749 flipY = isViewportFlipEnabledForDrawFBO() ? -1.0f : 1.0f;
4750 break;
4751 case SurfaceRotation::Rotated90Degrees:
4752 ASSERT(isViewportFlipEnabledForDrawFBO());
4753 flipX = 1.0f;
4754 flipY = 1.0f;
4755 std::swap(halfRenderAreaWidth, halfRenderAreaHeight);
4756 break;
4757 case SurfaceRotation::Rotated180Degrees:
4758 ASSERT(isViewportFlipEnabledForDrawFBO());
4759 flipX = -1.0f;
4760 flipY = 1.0f;
4761 break;
4762 case SurfaceRotation::Rotated270Degrees:
4763 ASSERT(isViewportFlipEnabledForDrawFBO());
4764 flipX = -1.0f;
4765 flipY = -1.0f;
4766 break;
4767 default:
4768 UNREACHABLE();
4769 break;
4770 }
4771
4772 GraphicsDriverUniformsExtended *driverUniformsExt =
4773 reinterpret_cast<GraphicsDriverUniformsExtended *>(ptr);
4774 driverUniformsExt->halfRenderArea = {halfRenderAreaWidth, halfRenderAreaHeight};
4775 driverUniformsExt->flipXY = {flipX, flipY};
4776 driverUniformsExt->negFlipXY = {flipX, -flipY};
4777 memcpy(&driverUniformsExt->fragRotation,
4778 &kFragRotationMatrices[mCurrentRotationDrawFramebuffer],
4779 sizeof(PreRotationMatrixValues));
4780 driverUniforms = &driverUniformsExt->common;
4781 }
4782 else
4783 {
4784 driverUniforms = reinterpret_cast<GraphicsDriverUniforms *>(ptr);
4785 }
4786
4787 gl::Rectangle glViewport = mState.getViewport();
4788 if (isRotatedAspectRatioForDrawFBO())
4789 {
4790 // The surface is rotated 90/270 degrees. This changes the aspect ratio of the surface.
4791 std::swap(glViewport.x, glViewport.y);
4792 std::swap(glViewport.width, glViewport.height);
4793 }
4794
4795 uint32_t xfbActiveUnpaused = mState.isTransformFeedbackActiveUnpaused();
4796
4797 float depthRangeNear = mState.getNearPlane();
4798 float depthRangeFar = mState.getFarPlane();
4799 float depthRangeDiff = depthRangeFar - depthRangeNear;
4800 int32_t numSamples = mDrawFramebuffer->getSamples();
4801
4802 // Copy and flush to the device.
4803 *driverUniforms = {
4804 {static_cast<float>(glViewport.x), static_cast<float>(glViewport.y),
4805 static_cast<float>(glViewport.width), static_cast<float>(glViewport.height)},
4806 mState.getEnabledClipDistances().bits(),
4807 xfbActiveUnpaused,
4808 static_cast<int32_t>(mXfbVertexCountPerInstance),
4809 numSamples,
4810 {},
4811 {},
4812 {depthRangeNear, depthRangeFar, depthRangeDiff, 0.0f}};
4813
4814 if (xfbActiveUnpaused)
4815 {
4816 TransformFeedbackVk *transformFeedbackVk =
4817 vk::GetImpl(mState.getCurrentTransformFeedback());
4818 transformFeedbackVk->getBufferOffsets(this, mXfbBaseVertex,
4819 driverUniforms->xfbBufferOffsets.data(),
4820 driverUniforms->xfbBufferOffsets.size());
4821 }
4822
4823 if (mState.hasValidAtomicCounterBuffer())
4824 {
4825 writeAtomicCounterBufferDriverUniformOffsets(driverUniforms->acbBufferOffsets.data(),
4826 driverUniforms->acbBufferOffsets.size());
4827 }
4828
4829 return updateDriverUniformsDescriptorSet(newBuffer, driverUniformSize,
4830 &mDriverUniforms[PipelineType::Graphics]);
4831 }
4832
handleDirtyComputeDriverUniforms()4833 angle::Result ContextVk::handleDirtyComputeDriverUniforms()
4834 {
4835 // Allocate a new region in the dynamic buffer.
4836 uint8_t *ptr;
4837 bool newBuffer;
4838 ANGLE_TRY(allocateDriverUniforms(sizeof(ComputeDriverUniforms),
4839 &mDriverUniforms[PipelineType::Compute], &ptr, &newBuffer));
4840
4841 // Copy and flush to the device.
4842 ComputeDriverUniforms *driverUniforms = reinterpret_cast<ComputeDriverUniforms *>(ptr);
4843 *driverUniforms = {};
4844
4845 if (mState.hasValidAtomicCounterBuffer())
4846 {
4847 writeAtomicCounterBufferDriverUniformOffsets(driverUniforms->acbBufferOffsets.data(),
4848 driverUniforms->acbBufferOffsets.size());
4849 }
4850
4851 return updateDriverUniformsDescriptorSet(newBuffer, sizeof(ComputeDriverUniforms),
4852 &mDriverUniforms[PipelineType::Compute]);
4853 }
4854
handleDirtyDriverUniformsBindingImpl(vk::CommandBuffer * commandBuffer,VkPipelineBindPoint bindPoint,DriverUniformsDescriptorSet * driverUniforms)4855 void ContextVk::handleDirtyDriverUniformsBindingImpl(vk::CommandBuffer *commandBuffer,
4856 VkPipelineBindPoint bindPoint,
4857 DriverUniformsDescriptorSet *driverUniforms)
4858 {
4859 // The descriptor pool that this descriptor set was allocated from needs to be retained when the
4860 // descriptor set is used in a new command. Since the descriptor pools are specific to each
4861 // ContextVk, we only need to retain them once to ensure the reference count and Serial are
4862 // updated correctly.
4863 if (!driverUniforms->descriptorPoolBinding.get().usedInRecordedCommands())
4864 {
4865 driverUniforms->descriptorPoolBinding.get().retain(&mResourceUseList);
4866 }
4867
4868 commandBuffer->bindDescriptorSets(
4869 mExecutable->getPipelineLayout(), bindPoint, DescriptorSetIndex::Internal, 1,
4870 &driverUniforms->descriptorSet, 1, &driverUniforms->dynamicOffset);
4871 }
4872
handleDirtyGraphicsDriverUniformsBinding(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)4873 angle::Result ContextVk::handleDirtyGraphicsDriverUniformsBinding(
4874 DirtyBits::Iterator *dirtyBitsIterator,
4875 DirtyBits dirtyBitMask)
4876 {
4877 // Bind the driver descriptor set.
4878 handleDirtyDriverUniformsBindingImpl(mRenderPassCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
4879 &mDriverUniforms[PipelineType::Graphics]);
4880 return angle::Result::Continue;
4881 }
4882
handleDirtyComputeDriverUniformsBinding()4883 angle::Result ContextVk::handleDirtyComputeDriverUniformsBinding()
4884 {
4885 // Bind the driver descriptor set.
4886 handleDirtyDriverUniformsBindingImpl(&mOutsideRenderPassCommands->getCommandBuffer(),
4887 VK_PIPELINE_BIND_POINT_COMPUTE,
4888 &mDriverUniforms[PipelineType::Compute]);
4889 return angle::Result::Continue;
4890 }
4891
allocateDriverUniforms(size_t driverUniformsSize,DriverUniformsDescriptorSet * driverUniforms,uint8_t ** ptrOut,bool * newBufferOut)4892 angle::Result ContextVk::allocateDriverUniforms(size_t driverUniformsSize,
4893 DriverUniformsDescriptorSet *driverUniforms,
4894 uint8_t **ptrOut,
4895 bool *newBufferOut)
4896 {
4897 // Allocate a new region in the dynamic buffer. The allocate call may put buffer into dynamic
4898 // buffer's mInflightBuffers. During command submission time, these inflight buffers are added
4899 // into context's mResourceUseList which will ensure they get tagged with queue serial number
4900 // before moving them into the free list.
4901 VkDeviceSize offset;
4902 ANGLE_TRY(driverUniforms->dynamicBuffer.allocate(this, driverUniformsSize, ptrOut, nullptr,
4903 &offset, newBufferOut));
4904
4905 driverUniforms->dynamicOffset = static_cast<uint32_t>(offset);
4906
4907 return angle::Result::Continue;
4908 }
4909
updateDriverUniformsDescriptorSet(bool newBuffer,size_t driverUniformsSize,DriverUniformsDescriptorSet * driverUniforms)4910 angle::Result ContextVk::updateDriverUniformsDescriptorSet(
4911 bool newBuffer,
4912 size_t driverUniformsSize,
4913 DriverUniformsDescriptorSet *driverUniforms)
4914 {
4915 ANGLE_TRY(driverUniforms->dynamicBuffer.flush(this));
4916
4917 if (!newBuffer)
4918 {
4919 return angle::Result::Continue;
4920 }
4921
4922 const vk::BufferHelper *buffer = driverUniforms->dynamicBuffer.getCurrentBuffer();
4923 vk::BufferSerial bufferSerial = buffer->getBufferSerial();
4924 // Look up in the cache first
4925 if (driverUniforms->descriptorSetCache.get(bufferSerial.getValue(),
4926 &driverUniforms->descriptorSet))
4927 {
4928 // The descriptor pool that this descriptor set was allocated from needs to be retained each
4929 // time the descriptor set is used in a new command.
4930 driverUniforms->descriptorPoolBinding.get().retain(&mResourceUseList);
4931 return angle::Result::Continue;
4932 }
4933
4934 // Allocate a new descriptor set.
4935 bool isCompute = getState().getProgramExecutable()->isCompute();
4936 PipelineType pipelineType = isCompute ? PipelineType::Compute : PipelineType::Graphics;
4937 bool newPoolAllocated;
4938 ANGLE_TRY(mDriverUniformsDescriptorPools[pipelineType].allocateSetsAndGetInfo(
4939 this, driverUniforms->descriptorSetLayout.get().ptr(), 1,
4940 &driverUniforms->descriptorPoolBinding, &driverUniforms->descriptorSet, &newPoolAllocated));
4941 mContextPerfCounters.descriptorSetsAllocated[pipelineType]++;
4942
4943 // Clear descriptor set cache. It may no longer be valid.
4944 if (newPoolAllocated)
4945 {
4946 driverUniforms->descriptorSetCache.clear();
4947 }
4948
4949 // Update the driver uniform descriptor set.
4950 VkDescriptorBufferInfo &bufferInfo = allocDescriptorBufferInfo();
4951 bufferInfo.buffer = buffer->getBuffer().getHandle();
4952 bufferInfo.offset = 0;
4953 bufferInfo.range = driverUniformsSize;
4954
4955 VkWriteDescriptorSet &writeInfo = allocWriteDescriptorSet();
4956 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
4957 writeInfo.dstSet = driverUniforms->descriptorSet;
4958 writeInfo.dstBinding = 0;
4959 writeInfo.dstArrayElement = 0;
4960 writeInfo.descriptorCount = 1;
4961 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
4962 writeInfo.pImageInfo = nullptr;
4963 writeInfo.pTexelBufferView = nullptr;
4964 writeInfo.pBufferInfo = &bufferInfo;
4965
4966 // Add into descriptor set cache
4967 driverUniforms->descriptorSetCache.insert(bufferSerial.getValue(),
4968 driverUniforms->descriptorSet);
4969
4970 return angle::Result::Continue;
4971 }
4972
handleError(VkResult errorCode,const char * file,const char * function,unsigned int line)4973 void ContextVk::handleError(VkResult errorCode,
4974 const char *file,
4975 const char *function,
4976 unsigned int line)
4977 {
4978 ASSERT(errorCode != VK_SUCCESS);
4979
4980 GLenum glErrorCode = DefaultGLErrorCode(errorCode);
4981
4982 std::stringstream errorStream;
4983 errorStream << "Internal Vulkan error (" << errorCode << "): " << VulkanResultString(errorCode)
4984 << ".";
4985
4986 if (errorCode == VK_ERROR_DEVICE_LOST)
4987 {
4988 WARN() << errorStream.str();
4989 handleDeviceLost();
4990 }
4991
4992 mErrors->handleError(glErrorCode, errorStream.str().c_str(), file, function, line);
4993 }
4994
updateActiveTextures(const gl::Context * context)4995 angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
4996 {
4997 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
4998 ASSERT(executable);
4999
5000 uint32_t prevMaxIndex = mActiveTexturesDesc.getMaxIndex();
5001 memset(mActiveTextures.data(), 0, sizeof(mActiveTextures[0]) * prevMaxIndex);
5002 mActiveTexturesDesc.reset();
5003
5004 const gl::ActiveTexturesCache &textures = mState.getActiveTexturesCache();
5005 const gl::ActiveTextureMask &activeTextures = executable->getActiveSamplersMask();
5006 const gl::ActiveTextureTypeArray &textureTypes = executable->getActiveSamplerTypes();
5007
5008 bool recreatePipelineLayout = false;
5009 FormatIndexMap<uint64_t> externalFormatIndexMap = {};
5010 FormatIndexMap<VkFormat> vkFormatIndexMap = {};
5011 for (size_t textureUnit : activeTextures)
5012 {
5013 gl::Texture *texture = textures[textureUnit];
5014 gl::TextureType textureType = textureTypes[textureUnit];
5015 ASSERT(textureType != gl::TextureType::InvalidEnum);
5016
5017 const bool isIncompleteTexture = texture == nullptr;
5018
5019 // Null textures represent incomplete textures.
5020 if (isIncompleteTexture)
5021 {
5022 ANGLE_TRY(getIncompleteTexture(
5023 context, textureType, executable->getSamplerFormatForTextureUnitIndex(textureUnit),
5024 &texture));
5025 }
5026
5027 TextureVk *textureVk = vk::GetImpl(texture);
5028 ASSERT(textureVk != nullptr);
5029
5030 vk::TextureUnit &activeTexture = mActiveTextures[textureUnit];
5031
5032 // Special handling of texture buffers. They have a buffer attached instead of an image.
5033 if (textureType == gl::TextureType::Buffer)
5034 {
5035 activeTexture.texture = textureVk;
5036 mActiveTexturesDesc.update(textureUnit, textureVk->getBufferViewSerial(),
5037 vk::SamplerSerial());
5038
5039 continue;
5040 }
5041
5042 if (!isIncompleteTexture && texture->isDepthOrStencil() &&
5043 shouldSwitchToReadOnlyDepthFeedbackLoopMode(context, texture))
5044 {
5045 // Special handling for deferred clears.
5046 ANGLE_TRY(mDrawFramebuffer->flushDeferredClears(this));
5047
5048 if (hasStartedRenderPass())
5049 {
5050 if (!textureVk->getImage().hasRenderPassUsageFlag(
5051 vk::RenderPassUsage::ReadOnlyAttachment))
5052 {
5053 // To enter depth feedback loop, we must flush and start a new renderpass.
5054 // Otherwise it will stick with writable layout and cause validation error.
5055 ANGLE_TRY(flushCommandsAndEndRenderPass());
5056 }
5057 else
5058 {
5059 mDrawFramebuffer->updateRenderPassReadOnlyDepthMode(this, mRenderPassCommands);
5060 }
5061 }
5062
5063 mDrawFramebuffer->setReadOnlyDepthFeedbackLoopMode(true);
5064 }
5065
5066 gl::Sampler *sampler = mState.getSampler(static_cast<uint32_t>(textureUnit));
5067 const SamplerVk *samplerVk = sampler ? vk::GetImpl(sampler) : nullptr;
5068
5069 const vk::SamplerHelper &samplerHelper =
5070 samplerVk ? samplerVk->getSampler() : textureVk->getSampler();
5071 const gl::SamplerState &samplerState =
5072 sampler ? sampler->getSamplerState() : texture->getSamplerState();
5073 activeTexture.texture = textureVk;
5074 activeTexture.sampler = &samplerHelper;
5075 activeTexture.srgbDecode = samplerState.getSRGBDecode();
5076
5077 if (activeTexture.srgbDecode == GL_SKIP_DECODE_EXT)
5078 {
5079 // Make sure we use the MUTABLE bit for the storage. Because the "skip decode" is a
5080 // Sampler state we might not have caught this setting in TextureVk::syncState.
5081 ANGLE_TRY(textureVk->ensureMutable(this));
5082 }
5083
5084 vk::ImageOrBufferViewSubresourceSerial imageViewSerial =
5085 textureVk->getImageViewSubresourceSerial(samplerState);
5086 mActiveTexturesDesc.update(textureUnit, imageViewSerial, samplerHelper.getSamplerSerial());
5087
5088 if (textureVk->getImage().hasImmutableSampler())
5089 {
5090 uint64_t externalFormat = textureVk->getImage().getExternalFormat();
5091 VkFormat vkFormat = textureVk->getImage().getFormat().actualImageVkFormat();
5092 if (externalFormat != 0)
5093 {
5094 externalFormatIndexMap[externalFormat] = static_cast<uint32_t>(textureUnit);
5095 }
5096 else
5097 {
5098 ASSERT(vkFormat != 0);
5099 vkFormatIndexMap[vkFormat] = static_cast<uint32_t>(textureUnit);
5100 }
5101 }
5102
5103 recreatePipelineLayout =
5104 textureVk->getAndResetImmutableSamplerDirtyState() || recreatePipelineLayout;
5105 }
5106
5107 if (!mExecutable->isImmutableSamplerFormatCompatible(externalFormatIndexMap, vkFormatIndexMap))
5108 {
5109 recreatePipelineLayout = true;
5110 }
5111
5112 // Recreate the pipeline layout, if necessary.
5113 if (recreatePipelineLayout)
5114 {
5115 ANGLE_TRY(mExecutable->createPipelineLayout(context, &mActiveTextures));
5116
5117 // The default uniforms descriptor set was reset during createPipelineLayout(), so mark them
5118 // dirty to get everything reallocated/rebound before the next draw.
5119 if (executable->hasDefaultUniforms())
5120 {
5121 if (mProgram)
5122 {
5123 mProgram->setAllDefaultUniformsDirty();
5124 }
5125 else if (mProgramPipeline)
5126 {
5127 mProgramPipeline->setAllDefaultUniformsDirty(context->getState());
5128 }
5129 }
5130 }
5131
5132 return angle::Result::Continue;
5133 }
5134
updateActiveImages(vk::CommandBufferHelper * commandBufferHelper)5135 angle::Result ContextVk::updateActiveImages(vk::CommandBufferHelper *commandBufferHelper)
5136 {
5137 const gl::State &glState = mState;
5138 const gl::ProgramExecutable *executable = glState.getProgramExecutable();
5139 ASSERT(executable);
5140
5141 mActiveImages.fill(nullptr);
5142
5143 const gl::ActiveTextureMask &activeImages = executable->getActiveImagesMask();
5144 const gl::ActiveTextureArray<gl::ShaderBitSet> &activeImageShaderBits =
5145 executable->getActiveImageShaderBits();
5146
5147 // Note: currently, the image layout is transitioned entirely even if only one level or layer is
5148 // used. This is an issue if one subresource of the image is used as framebuffer attachment and
5149 // the other as image. This is a similar issue to http://anglebug.com/2914. Another issue
5150 // however is if multiple subresources of the same image are used at the same time.
5151 // Inefficiencies aside, setting write dependency on the same image multiple times is not
5152 // supported. The following makes sure write dependencies are set only once per image.
5153 std::set<vk::ImageHelper *> alreadyProcessed;
5154
5155 for (size_t imageUnitIndex : activeImages)
5156 {
5157 const gl::ImageUnit &imageUnit = glState.getImageUnit(imageUnitIndex);
5158 const gl::Texture *texture = imageUnit.texture.get();
5159 if (texture == nullptr)
5160 {
5161 continue;
5162 }
5163
5164 TextureVk *textureVk = vk::GetImpl(texture);
5165 mActiveImages[imageUnitIndex] = textureVk;
5166
5167 // The image should be flushed and ready to use at this point. There may still be
5168 // lingering staged updates in its staging buffer for unused texture mip levels or
5169 // layers. Therefore we can't verify it has no staged updates right here.
5170 gl::ShaderBitSet shaderStages = activeImageShaderBits[imageUnitIndex];
5171 ASSERT(shaderStages.any());
5172
5173 // Special handling of texture buffers. They have a buffer attached instead of an image.
5174 if (texture->getType() == gl::TextureType::Buffer)
5175 {
5176 BufferVk *bufferVk = vk::GetImpl(textureVk->getBuffer().get());
5177 VkDeviceSize bufferOffset = 0;
5178 vk::BufferHelper &buffer = bufferVk->getBufferAndOffset(&bufferOffset);
5179
5180 // TODO: accept multiple stages in bufferWrite. http://anglebug.com/3573
5181 for (gl::ShaderType stage : shaderStages)
5182 {
5183 commandBufferHelper->bufferWrite(
5184 this, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
5185 vk::GetPipelineStage(stage), vk::AliasingMode::Disallowed, &buffer);
5186 }
5187
5188 textureVk->retainBufferViews(&mResourceUseList);
5189
5190 continue;
5191 }
5192
5193 vk::ImageHelper *image = &textureVk->getImage();
5194
5195 if (alreadyProcessed.find(image) != alreadyProcessed.end())
5196 {
5197 continue;
5198 }
5199 alreadyProcessed.insert(image);
5200
5201 vk::ImageLayout imageLayout;
5202 gl::ShaderType firstShader = shaderStages.first();
5203 gl::ShaderType lastShader = shaderStages.last();
5204 shaderStages.reset(firstShader);
5205 shaderStages.reset(lastShader);
5206 // We barrier against either:
5207 // - Vertex only
5208 // - Fragment only
5209 // - Pre-fragment only (vertex, geometry and tessellation together)
5210 if (shaderStages.any() || firstShader != lastShader)
5211 {
5212 imageLayout = lastShader == gl::ShaderType::Fragment
5213 ? vk::ImageLayout::AllGraphicsShadersWrite
5214 : vk::ImageLayout::PreFragmentShadersWrite;
5215 }
5216 else
5217 {
5218 imageLayout = kShaderWriteImageLayouts[firstShader];
5219 }
5220
5221 VkImageAspectFlags aspectFlags = image->getAspectFlags();
5222
5223 uint32_t layerStart = 0;
5224 uint32_t layerCount = image->getLayerCount();
5225 if (imageUnit.layered)
5226 {
5227 layerStart = imageUnit.layered;
5228 layerCount = 1;
5229 }
5230
5231 commandBufferHelper->imageWrite(
5232 this, gl::LevelIndex(static_cast<uint32_t>(imageUnit.level)), layerStart, layerCount,
5233 aspectFlags, imageLayout, vk::AliasingMode::Allowed, image);
5234 }
5235
5236 return angle::Result::Continue;
5237 }
5238
hasRecordedCommands()5239 bool ContextVk::hasRecordedCommands()
5240 {
5241 ASSERT(mOutsideRenderPassCommands && mRenderPassCommands);
5242 return !mOutsideRenderPassCommands->empty() || mRenderPassCommands->started();
5243 }
5244
flushImpl(const vk::Semaphore * signalSemaphore)5245 angle::Result ContextVk::flushImpl(const vk::Semaphore *signalSemaphore)
5246 {
5247 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::flushImpl");
5248
5249 // We must set this to false before calling flushCommandsAndEndRenderPass to prevent it from
5250 // calling back to flushImpl.
5251 mHasDeferredFlush = false;
5252 getShareGroupVk()->clearSyncObjectPendingFlush();
5253
5254 ANGLE_TRY(flushCommandsAndEndRenderPass());
5255
5256 if (mIsAnyHostVisibleBufferWritten)
5257 {
5258 // Make sure all writes to host-visible buffers are flushed. We have no way of knowing
5259 // whether any buffer will be mapped for readback in the future, and we can't afford to
5260 // flush and wait on a one-pipeline-barrier command buffer on every map().
5261 VkMemoryBarrier memoryBarrier = {};
5262 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
5263 memoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
5264 memoryBarrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT;
5265
5266 mOutsideRenderPassCommands->getCommandBuffer().memoryBarrier(
5267 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_HOST_BIT, &memoryBarrier);
5268 mIsAnyHostVisibleBufferWritten = false;
5269 }
5270
5271 if (mGpuEventsEnabled)
5272 {
5273 EventName eventName = GetTraceEventName("Primary", mPerfCounters.primaryBuffers);
5274 ANGLE_TRY(traceGpuEvent(&mOutsideRenderPassCommands->getCommandBuffer(),
5275 TRACE_EVENT_PHASE_END, eventName));
5276 }
5277 ANGLE_TRY(flushOutsideRenderPassCommands());
5278
5279 // We must add the per context dynamic buffers into mResourceUseList before submission so that
5280 // they get retained properly until GPU completes. We do not add current buffer into
5281 // mResourceUseList since they never get reused or freed until context gets destroyed, at which
5282 // time we always wait for GPU to finish before destroying the dynamic buffers.
5283 for (DriverUniformsDescriptorSet &driverUniform : mDriverUniforms)
5284 {
5285 driverUniform.dynamicBuffer.releaseInFlightBuffersToResourceUseList(this);
5286 }
5287 mDefaultUniformStorage.releaseInFlightBuffersToResourceUseList(this);
5288 mStagingBuffer.releaseInFlightBuffersToResourceUseList(this);
5289
5290 ANGLE_TRY(submitFrame(signalSemaphore));
5291
5292 mPerfCounters.renderPasses = 0;
5293 mPerfCounters.writeDescriptorSets = 0;
5294 mPerfCounters.flushedOutsideRenderPassCommandBuffers = 0;
5295 mPerfCounters.resolveImageCommands = 0;
5296
5297 ASSERT(mWaitSemaphores.empty());
5298 ASSERT(mWaitSemaphoreStageMasks.empty());
5299
5300 mPerfCounters.primaryBuffers++;
5301
5302 if (mGpuEventsEnabled)
5303 {
5304 EventName eventName = GetTraceEventName("Primary", mPerfCounters.primaryBuffers);
5305 ANGLE_TRY(traceGpuEvent(&mOutsideRenderPassCommands->getCommandBuffer(),
5306 TRACE_EVENT_PHASE_BEGIN, eventName));
5307 }
5308
5309 return angle::Result::Continue;
5310 }
5311
finishImpl()5312 angle::Result ContextVk::finishImpl()
5313 {
5314 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::finishImpl");
5315
5316 ANGLE_TRY(flushImpl(nullptr));
5317 ANGLE_TRY(mRenderer->finish(this, hasProtectedContent()));
5318
5319 clearAllGarbage();
5320
5321 if (mGpuEventsEnabled)
5322 {
5323 // This loop should in practice execute once since the queue is already idle.
5324 while (mInFlightGpuEventQueries.size() > 0)
5325 {
5326 ANGLE_TRY(checkCompletedGpuEvents());
5327 }
5328 // Recalculate the CPU/GPU time difference to account for clock drifting. Avoid
5329 // unnecessary synchronization if there is no event to be adjusted (happens when
5330 // finish() gets called multiple times towards the end of the application).
5331 if (mGpuEvents.size() > 0)
5332 {
5333 ANGLE_TRY(synchronizeCpuGpuTime());
5334 }
5335 }
5336
5337 return angle::Result::Continue;
5338 }
5339
addWaitSemaphore(VkSemaphore semaphore,VkPipelineStageFlags stageMask)5340 void ContextVk::addWaitSemaphore(VkSemaphore semaphore, VkPipelineStageFlags stageMask)
5341 {
5342 mWaitSemaphores.push_back(semaphore);
5343 mWaitSemaphoreStageMasks.push_back(stageMask);
5344 }
5345
getCommandPool() const5346 const vk::CommandPool &ContextVk::getCommandPool() const
5347 {
5348 return mCommandPool;
5349 }
5350
isSerialInUse(Serial serial) const5351 bool ContextVk::isSerialInUse(Serial serial) const
5352 {
5353 return serial > getLastCompletedQueueSerial();
5354 }
5355
checkCompletedCommands()5356 angle::Result ContextVk::checkCompletedCommands()
5357 {
5358 return mRenderer->checkCompletedCommands(this);
5359 }
5360
finishToSerial(Serial serial)5361 angle::Result ContextVk::finishToSerial(Serial serial)
5362 {
5363 return mRenderer->finishToSerial(this, serial);
5364 }
5365
getCompatibleRenderPass(const vk::RenderPassDesc & desc,vk::RenderPass ** renderPassOut)5366 angle::Result ContextVk::getCompatibleRenderPass(const vk::RenderPassDesc &desc,
5367 vk::RenderPass **renderPassOut)
5368 {
5369 // Note: Each context has it's own RenderPassCache so no locking needed.
5370 return mRenderPassCache.getCompatibleRenderPass(this, desc, renderPassOut);
5371 }
5372
getRenderPassWithOps(const vk::RenderPassDesc & desc,const vk::AttachmentOpsArray & ops,vk::RenderPass ** renderPassOut)5373 angle::Result ContextVk::getRenderPassWithOps(const vk::RenderPassDesc &desc,
5374 const vk::AttachmentOpsArray &ops,
5375 vk::RenderPass **renderPassOut)
5376 {
5377 // Note: Each context has it's own RenderPassCache so no locking needed.
5378 return mRenderPassCache.getRenderPassWithOps(this, desc, ops, renderPassOut);
5379 }
5380
getTimestamp(uint64_t * timestampOut)5381 angle::Result ContextVk::getTimestamp(uint64_t *timestampOut)
5382 {
5383 // The intent of this function is to query the timestamp without stalling the GPU.
5384 // Currently, that seems impossible, so instead, we are going to make a small submission
5385 // with just a timestamp query. First, the disjoint timer query extension says:
5386 //
5387 // > This will return the GL time after all previous commands have reached the GL server but
5388 // have not yet necessarily executed.
5389 //
5390 // The previous commands may be deferred at the moment and not yet flushed. The wording allows
5391 // us to make a submission to get the timestamp without flushing.
5392 //
5393 // Second:
5394 //
5395 // > By using a combination of this synchronous get command and the asynchronous timestamp
5396 // query object target, applications can measure the latency between when commands reach the
5397 // GL server and when they are realized in the framebuffer.
5398 //
5399 // This fits with the above strategy as well, although inevitably we are possibly
5400 // introducing a GPU bubble. This function directly generates a command buffer and submits
5401 // it instead of using the other member functions. This is to avoid changing any state,
5402 // such as the queue serial.
5403
5404 // Create a query used to receive the GPU timestamp
5405 VkDevice device = getDevice();
5406 vk::DeviceScoped<vk::DynamicQueryPool> timestampQueryPool(device);
5407 vk::QueryHelper timestampQuery;
5408 ANGLE_TRY(timestampQueryPool.get().init(this, VK_QUERY_TYPE_TIMESTAMP, 1));
5409 ANGLE_TRY(timestampQueryPool.get().allocateQuery(this, ×tampQuery, 1));
5410
5411 vk::ResourceUseList scratchResourceUseList;
5412
5413 // Record the command buffer
5414 vk::DeviceScoped<vk::PrimaryCommandBuffer> commandBatch(device);
5415 vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get();
5416
5417 ANGLE_TRY(mRenderer->getCommandBufferOneOff(this, hasProtectedContent(), &commandBuffer));
5418
5419 timestampQuery.writeTimestampToPrimary(this, &commandBuffer);
5420 timestampQuery.retain(&scratchResourceUseList);
5421 ANGLE_VK_TRY(this, commandBuffer.end());
5422
5423 // Create fence for the submission
5424 VkFenceCreateInfo fenceInfo = {};
5425 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
5426 fenceInfo.flags = 0;
5427
5428 vk::DeviceScoped<vk::Fence> fence(device);
5429 ANGLE_VK_TRY(this, fence.get().init(device, fenceInfo));
5430
5431 Serial throwAwaySerial;
5432 ANGLE_TRY(mRenderer->queueSubmitOneOff(this, std::move(commandBuffer), hasProtectedContent(),
5433 mContextPriority, &fence.get(),
5434 vk::SubmitPolicy::EnsureSubmitted, &throwAwaySerial));
5435
5436 // Wait for the submission to finish. Given no semaphores, there is hope that it would execute
5437 // in parallel with what's already running on the GPU.
5438 ANGLE_VK_TRY(this, fence.get().wait(device, mRenderer->getMaxFenceWaitTimeNs()));
5439 scratchResourceUseList.releaseResourceUsesAndUpdateSerials(throwAwaySerial);
5440
5441 // Get the query results
5442 vk::QueryResult result(1);
5443 ANGLE_TRY(timestampQuery.getUint64Result(this, &result));
5444 *timestampOut = result.getResult(vk::QueryResult::kDefaultResultIndex);
5445 timestampQueryPool.get().freeQuery(this, ×tampQuery);
5446
5447 // Convert results to nanoseconds.
5448 *timestampOut = static_cast<uint64_t>(
5449 *timestampOut *
5450 static_cast<double>(getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod));
5451
5452 return angle::Result::Continue;
5453 }
5454
invalidateDefaultAttribute(size_t attribIndex)5455 void ContextVk::invalidateDefaultAttribute(size_t attribIndex)
5456 {
5457 mDirtyDefaultAttribsMask.set(attribIndex);
5458 mGraphicsDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS);
5459 }
5460
invalidateDefaultAttributes(const gl::AttributesMask & dirtyMask)5461 void ContextVk::invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask)
5462 {
5463 if (dirtyMask.any())
5464 {
5465 mDirtyDefaultAttribsMask |= dirtyMask;
5466 mGraphicsDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS);
5467 }
5468 }
5469
updateDefaultAttribute(size_t attribIndex)5470 angle::Result ContextVk::updateDefaultAttribute(size_t attribIndex)
5471 {
5472 vk::DynamicBuffer &defaultBuffer = mDefaultAttribBuffers[attribIndex];
5473
5474 defaultBuffer.releaseInFlightBuffers(this);
5475
5476 uint8_t *ptr;
5477 VkBuffer bufferHandle = VK_NULL_HANDLE;
5478 VkDeviceSize offset = 0;
5479 ANGLE_TRY(
5480 defaultBuffer.allocate(this, kDefaultValueSize, &ptr, &bufferHandle, &offset, nullptr));
5481
5482 const gl::State &glState = mState;
5483 const gl::VertexAttribCurrentValueData &defaultValue =
5484 glState.getVertexAttribCurrentValues()[attribIndex];
5485 memcpy(ptr, &defaultValue.Values, kDefaultValueSize);
5486 ASSERT(!defaultBuffer.isCoherent());
5487 ANGLE_TRY(defaultBuffer.flush(this));
5488
5489 return mVertexArray->updateDefaultAttrib(this, attribIndex, bufferHandle,
5490 defaultBuffer.getCurrentBuffer(),
5491 static_cast<uint32_t>(offset));
5492 }
5493
getDriverUniformsDescriptorSetDesc(VkShaderStageFlags shaderStages) const5494 vk::DescriptorSetLayoutDesc ContextVk::getDriverUniformsDescriptorSetDesc(
5495 VkShaderStageFlags shaderStages) const
5496 {
5497 vk::DescriptorSetLayoutDesc desc;
5498 desc.update(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, shaderStages, nullptr);
5499 return desc;
5500 }
5501
shouldEmulateSeamfulCubeMapSampling() const5502 bool ContextVk::shouldEmulateSeamfulCubeMapSampling() const
5503 {
5504 // Only allow seamful cube map sampling in non-webgl ES2.
5505 if (mState.getClientMajorVersion() != 2 || mState.isWebGL())
5506 {
5507 return false;
5508 }
5509
5510 if (mRenderer->getFeatures().disallowSeamfulCubeMapEmulation.enabled)
5511 {
5512 return false;
5513 }
5514
5515 return true;
5516 }
5517
onBufferReleaseToExternal(const vk::BufferHelper & buffer)5518 angle::Result ContextVk::onBufferReleaseToExternal(const vk::BufferHelper &buffer)
5519 {
5520 if (mRenderPassCommands->usesBuffer(buffer))
5521 {
5522 return flushCommandsAndEndRenderPass();
5523 }
5524 return angle::Result::Continue;
5525 }
5526
onImageReleaseToExternal(const vk::ImageHelper & image)5527 angle::Result ContextVk::onImageReleaseToExternal(const vk::ImageHelper &image)
5528 {
5529 if (IsRenderPassStartedAndUsesImage(*mRenderPassCommands, image))
5530 {
5531 return flushCommandsAndEndRenderPass();
5532 }
5533 return angle::Result::Continue;
5534 }
5535
beginNewRenderPass(const vk::Framebuffer & framebuffer,const gl::Rectangle & renderArea,const vk::RenderPassDesc & renderPassDesc,const vk::AttachmentOpsArray & renderPassAttachmentOps,const vk::PackedAttachmentCount colorAttachmentCount,const vk::PackedAttachmentIndex depthStencilAttachmentIndex,const vk::PackedClearValuesArray & clearValues,vk::CommandBuffer ** commandBufferOut)5536 angle::Result ContextVk::beginNewRenderPass(
5537 const vk::Framebuffer &framebuffer,
5538 const gl::Rectangle &renderArea,
5539 const vk::RenderPassDesc &renderPassDesc,
5540 const vk::AttachmentOpsArray &renderPassAttachmentOps,
5541 const vk::PackedAttachmentCount colorAttachmentCount,
5542 const vk::PackedAttachmentIndex depthStencilAttachmentIndex,
5543 const vk::PackedClearValuesArray &clearValues,
5544 vk::CommandBuffer **commandBufferOut)
5545 {
5546 // Next end any currently outstanding renderPass
5547 ANGLE_TRY(flushCommandsAndEndRenderPass());
5548
5549 mRenderPassCommands->beginRenderPass(
5550 framebuffer, renderArea, renderPassDesc, renderPassAttachmentOps, colorAttachmentCount,
5551 depthStencilAttachmentIndex, clearValues, commandBufferOut);
5552 mPerfCounters.renderPasses++;
5553
5554 return angle::Result::Continue;
5555 }
5556
startRenderPass(gl::Rectangle renderArea,vk::CommandBuffer ** commandBufferOut,bool * renderPassDescChangedOut)5557 angle::Result ContextVk::startRenderPass(gl::Rectangle renderArea,
5558 vk::CommandBuffer **commandBufferOut,
5559 bool *renderPassDescChangedOut)
5560 {
5561 ANGLE_TRY(mDrawFramebuffer->startNewRenderPass(this, renderArea, &mRenderPassCommandBuffer,
5562 renderPassDescChangedOut));
5563
5564 // Make sure the render pass is not restarted if it is started by UtilsVk (as opposed to
5565 // setupDraw(), which clears this bit automatically).
5566 mGraphicsDirtyBits.reset(DIRTY_BIT_RENDER_PASS);
5567
5568 ANGLE_TRY(resumeRenderPassQueriesIfActive());
5569
5570 const gl::DepthStencilState &dsState = mState.getDepthStencilState();
5571 vk::ResourceAccess depthAccess = GetDepthAccess(dsState);
5572 vk::ResourceAccess stencilAccess = GetStencilAccess(dsState);
5573 mRenderPassCommands->onDepthAccess(depthAccess);
5574 mRenderPassCommands->onStencilAccess(stencilAccess);
5575
5576 mDrawFramebuffer->updateRenderPassReadOnlyDepthMode(this, mRenderPassCommands);
5577
5578 if (commandBufferOut)
5579 {
5580 *commandBufferOut = mRenderPassCommandBuffer;
5581 }
5582
5583 return angle::Result::Continue;
5584 }
5585
startNextSubpass()5586 void ContextVk::startNextSubpass()
5587 {
5588 ASSERT(hasStartedRenderPass());
5589
5590 mRenderPassCommands->getCommandBuffer().nextSubpass(VK_SUBPASS_CONTENTS_INLINE);
5591
5592 // The graphics pipelines are bound to a subpass, so update the subpass as well.
5593 mGraphicsPipelineDesc->nextSubpass(&mGraphicsPipelineTransition);
5594 }
5595
restoreFinishedRenderPass(vk::Framebuffer * framebuffer)5596 void ContextVk::restoreFinishedRenderPass(vk::Framebuffer *framebuffer)
5597 {
5598 if (mRenderPassCommandBuffer != nullptr)
5599 {
5600 // The render pass isn't finished yet, so nothing to restore.
5601 return;
5602 }
5603
5604 if (mRenderPassCommands->started() &&
5605 mRenderPassCommands->getFramebufferHandle() == framebuffer->getHandle())
5606 {
5607 // There is already a render pass open for this framebuffer, so just restore the
5608 // pointer rather than starting a whole new render pass. One possible path here
5609 // is if the draw framebuffer binding has changed from FBO A -> B -> A, without
5610 // any commands that started a new render pass for FBO B (such as a clear being
5611 // issued that was deferred).
5612 mRenderPassCommandBuffer = &mRenderPassCommands->getCommandBuffer();
5613 ASSERT(hasStartedRenderPass());
5614 }
5615 }
5616
getCurrentSubpassIndex() const5617 uint32_t ContextVk::getCurrentSubpassIndex() const
5618 {
5619 return mGraphicsPipelineDesc->getSubpass();
5620 }
5621
getCurrentViewCount() const5622 uint32_t ContextVk::getCurrentViewCount() const
5623 {
5624 ASSERT(mDrawFramebuffer);
5625 return mDrawFramebuffer->getRenderPassDesc().viewCount();
5626 }
5627
flushCommandsAndEndRenderPassImpl()5628 angle::Result ContextVk::flushCommandsAndEndRenderPassImpl()
5629 {
5630 // Ensure we flush the RenderPass *after* the prior commands.
5631 ANGLE_TRY(flushOutsideRenderPassCommands());
5632 ASSERT(mOutsideRenderPassCommands->empty());
5633
5634 if (!mRenderPassCommands->started())
5635 {
5636 onRenderPassFinished();
5637 return angle::Result::Continue;
5638 }
5639
5640 mCurrentTransformFeedbackBuffers.clear();
5641
5642 // Reset serials for XFB if active.
5643 if (mState.isTransformFeedbackActiveUnpaused())
5644 {
5645 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
5646 ASSERT(executable);
5647 size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
5648
5649 TransformFeedbackVk *transformFeedbackVk =
5650 vk::GetImpl(mState.getCurrentTransformFeedback());
5651
5652 populateTransformFeedbackBufferSet(xfbBufferCount, transformFeedbackVk->getBufferHelpers());
5653 }
5654
5655 onRenderPassFinished();
5656
5657 if (mGpuEventsEnabled)
5658 {
5659 EventName eventName = GetTraceEventName("RP", mPerfCounters.renderPasses);
5660 ANGLE_TRY(traceGpuEvent(&mOutsideRenderPassCommands->getCommandBuffer(),
5661 TRACE_EVENT_PHASE_BEGIN, eventName));
5662 ANGLE_TRY(flushOutsideRenderPassCommands());
5663 }
5664
5665 addOverlayUsedBuffersCount(mRenderPassCommands);
5666
5667 pauseTransformFeedbackIfActiveUnpaused();
5668
5669 mRenderPassCommands->endRenderPass(this);
5670
5671 if (vk::CommandBufferHelper::kEnableCommandStreamDiagnostics)
5672 {
5673 mRenderPassCommands->addCommandDiagnostics(this);
5674 }
5675
5676 vk::RenderPass *renderPass = nullptr;
5677 ANGLE_TRY(getRenderPassWithOps(mRenderPassCommands->getRenderPassDesc(),
5678 mRenderPassCommands->getAttachmentOps(), &renderPass));
5679
5680 ANGLE_TRY(mRenderer->flushRenderPassCommands(this, hasProtectedContent(), *renderPass,
5681 &mRenderPassCommands));
5682
5683 if (mGpuEventsEnabled)
5684 {
5685 EventName eventName = GetTraceEventName("RP", mPerfCounters.renderPasses);
5686 ANGLE_TRY(traceGpuEvent(&mOutsideRenderPassCommands->getCommandBuffer(),
5687 TRACE_EVENT_PHASE_END, eventName));
5688 ANGLE_TRY(flushOutsideRenderPassCommands());
5689 }
5690
5691 if (mHasDeferredFlush)
5692 {
5693 // If we have deferred glFlush call in the middle of renderpass, flush them now.
5694 ANGLE_TRY(flushImpl(nullptr));
5695 }
5696
5697 return angle::Result::Continue;
5698 }
5699
flushCommandsAndEndRenderPass()5700 angle::Result ContextVk::flushCommandsAndEndRenderPass()
5701 {
5702 bool isRenderPassStarted = mRenderPassCommands->started();
5703
5704 ANGLE_TRY(flushCommandsAndEndRenderPassImpl());
5705
5706 // Set dirty bits if render pass was open (and thus has been closed).
5707 if (isRenderPassStarted)
5708 {
5709 mGraphicsDirtyBits |= mNewGraphicsCommandBufferDirtyBits;
5710
5711 // Restart at subpass 0.
5712 mGraphicsPipelineDesc->resetSubpass(&mGraphicsPipelineTransition);
5713 }
5714
5715 return angle::Result::Continue;
5716 }
5717
flushDirtyGraphicsRenderPass(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)5718 angle::Result ContextVk::flushDirtyGraphicsRenderPass(DirtyBits::Iterator *dirtyBitsIterator,
5719 DirtyBits dirtyBitMask)
5720 {
5721 ASSERT(mRenderPassCommands->started());
5722
5723 ANGLE_TRY(flushCommandsAndEndRenderPassImpl());
5724
5725 // Set dirty bits that need processing on new render pass on the dirty bits iterator that's
5726 // being processed right now.
5727 dirtyBitsIterator->setLaterBits(mNewGraphicsCommandBufferDirtyBits & dirtyBitMask);
5728
5729 // Additionally, make sure any dirty bits not included in the mask are left for future
5730 // processing. Note that |dirtyBitMask| is removed from |mNewGraphicsCommandBufferDirtyBits|
5731 // after dirty bits are iterated, so there's no need to mask them out.
5732 mGraphicsDirtyBits |= mNewGraphicsCommandBufferDirtyBits;
5733
5734 // Restart at subpass 0.
5735 mGraphicsPipelineDesc->resetSubpass(&mGraphicsPipelineTransition);
5736
5737 return angle::Result::Continue;
5738 }
5739
syncExternalMemory()5740 angle::Result ContextVk::syncExternalMemory()
5741 {
5742 VkMemoryBarrier memoryBarrier = {};
5743 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
5744 memoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
5745 memoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
5746
5747 mOutsideRenderPassCommands->getCommandBuffer().memoryBarrier(
5748 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, &memoryBarrier);
5749 return angle::Result::Continue;
5750 }
5751
addCommandBufferDiagnostics(const std::string & commandBufferDiagnostics)5752 void ContextVk::addCommandBufferDiagnostics(const std::string &commandBufferDiagnostics)
5753 {
5754 mCommandBufferDiagnostics.push_back(commandBufferDiagnostics);
5755 }
5756
dumpCommandStreamDiagnostics()5757 void ContextVk::dumpCommandStreamDiagnostics()
5758 {
5759 std::ostream &out = std::cout;
5760
5761 if (mCommandBufferDiagnostics.empty())
5762 return;
5763
5764 out << "digraph {\n"
5765 << " node [shape=plaintext fontname=\"Consolas\"]\n";
5766
5767 for (size_t index = 0; index < mCommandBufferDiagnostics.size(); ++index)
5768 {
5769 const std::string &payload = mCommandBufferDiagnostics[index];
5770 out << " cb" << index << " [label =\"" << payload << "\"];\n";
5771 }
5772
5773 for (size_t index = 0; index < mCommandBufferDiagnostics.size() - 1; ++index)
5774 {
5775 out << " cb" << index << " -> cb" << index + 1 << "\n";
5776 }
5777
5778 mCommandBufferDiagnostics.clear();
5779
5780 out << "}\n";
5781 }
5782
initIndexTypeMap()5783 void ContextVk::initIndexTypeMap()
5784 {
5785 // Init gles-vulkan index type map
5786 mIndexTypeMap[gl::DrawElementsType::UnsignedByte] =
5787 mRenderer->getFeatures().supportsIndexTypeUint8.enabled ? VK_INDEX_TYPE_UINT8_EXT
5788 : VK_INDEX_TYPE_UINT16;
5789 mIndexTypeMap[gl::DrawElementsType::UnsignedShort] = VK_INDEX_TYPE_UINT16;
5790 mIndexTypeMap[gl::DrawElementsType::UnsignedInt] = VK_INDEX_TYPE_UINT32;
5791 }
5792
getVkIndexType(gl::DrawElementsType glIndexType) const5793 VkIndexType ContextVk::getVkIndexType(gl::DrawElementsType glIndexType) const
5794 {
5795 return mIndexTypeMap[glIndexType];
5796 }
5797
getVkIndexTypeSize(gl::DrawElementsType glIndexType) const5798 size_t ContextVk::getVkIndexTypeSize(gl::DrawElementsType glIndexType) const
5799 {
5800 gl::DrawElementsType elementsType = shouldConvertUint8VkIndexType(glIndexType)
5801 ? gl::DrawElementsType::UnsignedShort
5802 : glIndexType;
5803 ASSERT(elementsType < gl::DrawElementsType::EnumCount);
5804
5805 // Use GetDrawElementsTypeSize() to get the size
5806 return static_cast<size_t>(gl::GetDrawElementsTypeSize(elementsType));
5807 }
5808
shouldConvertUint8VkIndexType(gl::DrawElementsType glIndexType) const5809 bool ContextVk::shouldConvertUint8VkIndexType(gl::DrawElementsType glIndexType) const
5810 {
5811 return (glIndexType == gl::DrawElementsType::UnsignedByte &&
5812 !mRenderer->getFeatures().supportsIndexTypeUint8.enabled);
5813 }
5814
flushOutsideRenderPassCommands()5815 angle::Result ContextVk::flushOutsideRenderPassCommands()
5816 {
5817 if (mOutsideRenderPassCommands->empty())
5818 {
5819 return angle::Result::Continue;
5820 }
5821
5822 addOverlayUsedBuffersCount(mOutsideRenderPassCommands);
5823
5824 if (vk::CommandBufferHelper::kEnableCommandStreamDiagnostics)
5825 {
5826 mOutsideRenderPassCommands->addCommandDiagnostics(this);
5827 }
5828
5829 ANGLE_TRY(mRenderer->flushOutsideRPCommands(this, hasProtectedContent(),
5830 &mOutsideRenderPassCommands));
5831
5832 // Make sure appropriate dirty bits are set, in case another thread makes a submission before
5833 // the next dispatch call.
5834 mComputeDirtyBits |= mNewComputeCommandBufferDirtyBits;
5835
5836 mPerfCounters.flushedOutsideRenderPassCommandBuffers++;
5837 return angle::Result::Continue;
5838 }
5839
beginRenderPassQuery(QueryVk * queryVk)5840 angle::Result ContextVk::beginRenderPassQuery(QueryVk *queryVk)
5841 {
5842 // Emit debug-util markers before calling the query command.
5843 ANGLE_TRY(handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InRenderPassCmdBufQueryCmd));
5844
5845 // To avoid complexity, we always start and end these queries inside the render pass. If the
5846 // render pass has not yet started, the query is deferred until it does.
5847 if (mRenderPassCommandBuffer)
5848 {
5849 ANGLE_TRY(queryVk->getQueryHelper()->beginRenderPassQuery(this));
5850
5851 // Update rasterizer discard emulation with primitives generated query if necessary.
5852 if (queryVk->getType() == gl::QueryType::PrimitivesGenerated)
5853 {
5854 updateRasterizerDiscardEnabled(true);
5855 }
5856 }
5857
5858 gl::QueryType type = queryVk->getType();
5859
5860 ASSERT(mActiveRenderPassQueries[type] == nullptr);
5861 mActiveRenderPassQueries[type] = queryVk;
5862
5863 return angle::Result::Continue;
5864 }
5865
endRenderPassQuery(QueryVk * queryVk)5866 angle::Result ContextVk::endRenderPassQuery(QueryVk *queryVk)
5867 {
5868 // Emit debug-util markers before calling the query command.
5869 ANGLE_TRY(handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InRenderPassCmdBufQueryCmd));
5870
5871 if (mRenderPassCommandBuffer)
5872 {
5873 queryVk->getQueryHelper()->endRenderPassQuery(this);
5874
5875 // Update rasterizer discard emulation with primitives generated query if necessary.
5876 if (queryVk->getType() == gl::QueryType::PrimitivesGenerated)
5877 {
5878 updateRasterizerDiscardEnabled(false);
5879 }
5880 }
5881
5882 gl::QueryType type = queryVk->getType();
5883
5884 ASSERT(mActiveRenderPassQueries[type] == queryVk);
5885 mActiveRenderPassQueries[type] = nullptr;
5886
5887 return angle::Result::Continue;
5888 }
5889
pauseRenderPassQueriesIfActive()5890 void ContextVk::pauseRenderPassQueriesIfActive()
5891 {
5892 if (mRenderPassCommandBuffer == nullptr)
5893 {
5894 return;
5895 }
5896
5897 for (QueryVk *activeQuery : mActiveRenderPassQueries)
5898 {
5899 if (activeQuery)
5900 {
5901 activeQuery->onRenderPassEnd(this);
5902
5903 // No need to update rasterizer discard emulation with primitives generated query. The
5904 // state will be updated when the next render pass starts.
5905 }
5906 }
5907 }
5908
resumeRenderPassQueriesIfActive()5909 angle::Result ContextVk::resumeRenderPassQueriesIfActive()
5910 {
5911 ASSERT(mRenderPassCommandBuffer);
5912
5913 // Note: these queries should be processed in order. See comment in QueryVk::onRenderPassStart.
5914 for (QueryVk *activeQuery : mActiveRenderPassQueries)
5915 {
5916 if (activeQuery)
5917 {
5918 ANGLE_TRY(activeQuery->onRenderPassStart(this));
5919
5920 // Update rasterizer discard emulation with primitives generated query if necessary.
5921 if (activeQuery->getType() == gl::QueryType::PrimitivesGenerated)
5922 {
5923 updateRasterizerDiscardEnabled(true);
5924 }
5925 }
5926 }
5927
5928 return angle::Result::Continue;
5929 }
5930
doesPrimitivesGeneratedQuerySupportRasterizerDiscard() const5931 bool ContextVk::doesPrimitivesGeneratedQuerySupportRasterizerDiscard() const
5932 {
5933 // TODO: If primitives generated is implemented with VK_EXT_primitives_generated_query, check
5934 // the corresponding feature bit. http://anglebug.com/5430.
5935
5936 // If primitives generated is emulated with pipeline statistics query, it's unknown on which
5937 // hardware rasterizer discard is supported. Assume it's supported on none.
5938 if (getFeatures().supportsPipelineStatisticsQuery.enabled)
5939 {
5940 return false;
5941 }
5942
5943 return true;
5944 }
5945
isEmulatingRasterizerDiscardDuringPrimitivesGeneratedQuery(bool isPrimitivesGeneratedQueryActive) const5946 bool ContextVk::isEmulatingRasterizerDiscardDuringPrimitivesGeneratedQuery(
5947 bool isPrimitivesGeneratedQueryActive) const
5948 {
5949 return isPrimitivesGeneratedQueryActive && mState.isRasterizerDiscardEnabled() &&
5950 !doesPrimitivesGeneratedQuerySupportRasterizerDiscard();
5951 }
5952
getActiveRenderPassQuery(gl::QueryType queryType) const5953 QueryVk *ContextVk::getActiveRenderPassQuery(gl::QueryType queryType) const
5954 {
5955 return mActiveRenderPassQueries[queryType];
5956 }
5957
isRobustResourceInitEnabled() const5958 bool ContextVk::isRobustResourceInitEnabled() const
5959 {
5960 return mState.isRobustResourceInitEnabled();
5961 }
5962
5963 template <typename T, const T *VkWriteDescriptorSet::*pInfo>
growDesciptorCapacity(std::vector<T> * descriptorVector,size_t newSize)5964 void ContextVk::growDesciptorCapacity(std::vector<T> *descriptorVector, size_t newSize)
5965 {
5966 const T *const oldInfoStart = descriptorVector->empty() ? nullptr : &(*descriptorVector)[0];
5967 size_t newCapacity = std::max(descriptorVector->capacity() << 1, newSize);
5968 descriptorVector->reserve(newCapacity);
5969
5970 if (oldInfoStart)
5971 {
5972 // patch mWriteInfo with new BufferInfo/ImageInfo pointers
5973 for (VkWriteDescriptorSet &set : mWriteDescriptorSets)
5974 {
5975 if (set.*pInfo)
5976 {
5977 size_t index = set.*pInfo - oldInfoStart;
5978 set.*pInfo = &(*descriptorVector)[index];
5979 }
5980 }
5981 }
5982 }
5983
5984 template <typename T, const T *VkWriteDescriptorSet::*pInfo>
allocDescriptorInfos(std::vector<T> * descriptorVector,size_t count)5985 T *ContextVk::allocDescriptorInfos(std::vector<T> *descriptorVector, size_t count)
5986 {
5987 size_t oldSize = descriptorVector->size();
5988 size_t newSize = oldSize + count;
5989 if (newSize > descriptorVector->capacity())
5990 {
5991 // If we have reached capacity, grow the storage and patch the descriptor set with new
5992 // buffer info pointer
5993 growDesciptorCapacity<T, pInfo>(descriptorVector, newSize);
5994 }
5995 descriptorVector->resize(newSize);
5996 return &(*descriptorVector)[oldSize];
5997 }
5998
allocDescriptorBufferInfos(size_t count)5999 VkDescriptorBufferInfo *ContextVk::allocDescriptorBufferInfos(size_t count)
6000 {
6001 return allocDescriptorInfos<VkDescriptorBufferInfo, &VkWriteDescriptorSet::pBufferInfo>(
6002 &mDescriptorBufferInfos, count);
6003 }
6004
allocDescriptorImageInfos(size_t count)6005 VkDescriptorImageInfo *ContextVk::allocDescriptorImageInfos(size_t count)
6006 {
6007 return allocDescriptorInfos<VkDescriptorImageInfo, &VkWriteDescriptorSet::pImageInfo>(
6008 &mDescriptorImageInfos, count);
6009 }
6010
allocWriteDescriptorSets(size_t count)6011 VkWriteDescriptorSet *ContextVk::allocWriteDescriptorSets(size_t count)
6012 {
6013 mPerfCounters.writeDescriptorSets += count;
6014
6015 size_t oldSize = mWriteDescriptorSets.size();
6016 size_t newSize = oldSize + count;
6017 mWriteDescriptorSets.resize(newSize);
6018 return &mWriteDescriptorSets[oldSize];
6019 }
6020
setDefaultUniformBlocksMinSizeForTesting(size_t minSize)6021 void ContextVk::setDefaultUniformBlocksMinSizeForTesting(size_t minSize)
6022 {
6023 mDefaultUniformStorage.setMinimumSizeForTesting(minSize);
6024 }
6025
initializeMultisampleTextureToBlack(const gl::Context * context,gl::Texture * glTexture)6026 angle::Result ContextVk::initializeMultisampleTextureToBlack(const gl::Context *context,
6027 gl::Texture *glTexture)
6028 {
6029 ASSERT(glTexture->getType() == gl::TextureType::_2DMultisample);
6030 TextureVk *textureVk = vk::GetImpl(glTexture);
6031
6032 return textureVk->initializeContents(context, gl::ImageIndex::Make2DMultisample());
6033 }
6034
onProgramExecutableReset(ProgramExecutableVk * executableVk)6035 void ContextVk::onProgramExecutableReset(ProgramExecutableVk *executableVk)
6036 {
6037 const gl::ProgramExecutable *executable = getState().getProgramExecutable();
6038 if (!executable)
6039 {
6040 return;
6041 }
6042
6043 // Only do this for the currently bound ProgramExecutableVk, since Program A can be linked while
6044 // Program B is currently in use and we don't want to reset/invalidate Program B's pipeline.
6045 if (executableVk != mExecutable)
6046 {
6047 return;
6048 }
6049
6050 // Reset *ContextVk::mCurrentGraphicsPipeline, since programInfo.release() freed the
6051 // PipelineHelper that it's currently pointing to.
6052 // TODO(http://anglebug.com/5624): rework updateActiveTextures(), createPipelineLayout(),
6053 // handleDirtyGraphicsPipeline(), and ProgramPipelineVk::link().
6054 resetCurrentGraphicsPipeline();
6055
6056 if (executable->isCompute())
6057 {
6058 invalidateCurrentComputePipeline();
6059 }
6060 else
6061 {
6062 invalidateCurrentGraphicsPipeline();
6063 }
6064 }
6065
updateRenderPassDepthStencilAccess()6066 angle::Result ContextVk::updateRenderPassDepthStencilAccess()
6067 {
6068 if (hasStartedRenderPass() && mDrawFramebuffer->getDepthStencilRenderTarget())
6069 {
6070 const gl::DepthStencilState &dsState = mState.getDepthStencilState();
6071 vk::ResourceAccess depthAccess = GetDepthAccess(dsState);
6072 vk::ResourceAccess stencilAccess = GetStencilAccess(dsState);
6073
6074 if ((depthAccess == vk::ResourceAccess::Write ||
6075 stencilAccess == vk::ResourceAccess::Write) &&
6076 mDrawFramebuffer->isReadOnlyDepthFeedbackLoopMode())
6077 {
6078 // If we are switching out of read only mode and we are in feedback loop, we must end
6079 // renderpass here. Otherwise, updating it to writeable layout will produce a writable
6080 // feedback loop that is illegal in vulkan and will trigger validation errors that depth
6081 // texture is using the writable layout.
6082 ANGLE_TRY(flushCommandsAndEndRenderPass());
6083 // Clear read-only depth feedback mode.
6084 mDrawFramebuffer->setReadOnlyDepthFeedbackLoopMode(false);
6085 }
6086 else
6087 {
6088 mRenderPassCommands->onDepthAccess(depthAccess);
6089 mRenderPassCommands->onStencilAccess(stencilAccess);
6090
6091 mDrawFramebuffer->updateRenderPassReadOnlyDepthMode(this, mRenderPassCommands);
6092 }
6093 }
6094
6095 return angle::Result::Continue;
6096 }
6097
shouldSwitchToReadOnlyDepthFeedbackLoopMode(const gl::Context * context,gl::Texture * texture) const6098 bool ContextVk::shouldSwitchToReadOnlyDepthFeedbackLoopMode(const gl::Context *context,
6099 gl::Texture *texture) const
6100 {
6101 ASSERT(texture->isDepthOrStencil());
6102
6103 const gl::ProgramExecutable *programExecutable = mState.getProgramExecutable();
6104
6105 // When running compute we don't have a draw FBO.
6106 if (programExecutable->isCompute())
6107 {
6108 return false;
6109 }
6110
6111 // The "readOnlyDepthMode" feature enables read-only depth-stencil feedback loops. We
6112 // only switch to "read-only" mode when there's loop. We track the depth-stencil access
6113 // mode in the RenderPass. The tracking tells us when we can retroactively go back and
6114 // change the RenderPass to read-only. If there are any writes we need to break and
6115 // finish the current RP before starting the read-only one.
6116 return texture->isBoundToFramebuffer(mDrawFramebuffer->getState().getFramebufferSerial()) &&
6117 !mState.isDepthWriteEnabled() && !mDrawFramebuffer->isReadOnlyDepthFeedbackLoopMode();
6118 }
6119
onResourceAccess(const vk::CommandBufferAccess & access)6120 angle::Result ContextVk::onResourceAccess(const vk::CommandBufferAccess &access)
6121 {
6122 ANGLE_TRY(flushCommandBuffersIfNecessary(access));
6123
6124 for (const vk::CommandBufferImageAccess &imageAccess : access.getReadImages())
6125 {
6126 ASSERT(!IsRenderPassStartedAndUsesImage(*mRenderPassCommands, *imageAccess.image));
6127
6128 imageAccess.image->recordReadBarrier(this, imageAccess.aspectFlags, imageAccess.imageLayout,
6129 &mOutsideRenderPassCommands->getCommandBuffer());
6130 imageAccess.image->retain(&mResourceUseList);
6131 }
6132
6133 for (const vk::CommandBufferImageWrite &imageWrite : access.getWriteImages())
6134 {
6135 ASSERT(!IsRenderPassStartedAndUsesImage(*mRenderPassCommands, *imageWrite.access.image));
6136
6137 imageWrite.access.image->recordWriteBarrier(
6138 this, imageWrite.access.aspectFlags, imageWrite.access.imageLayout,
6139 &mOutsideRenderPassCommands->getCommandBuffer());
6140 imageWrite.access.image->retain(&mResourceUseList);
6141 imageWrite.access.image->onWrite(imageWrite.levelStart, imageWrite.levelCount,
6142 imageWrite.layerStart, imageWrite.layerCount,
6143 imageWrite.access.aspectFlags);
6144 }
6145
6146 for (const vk::CommandBufferBufferAccess &bufferAccess : access.getReadBuffers())
6147 {
6148 ASSERT(!mRenderPassCommands->usesBufferForWrite(*bufferAccess.buffer));
6149 ASSERT(!mOutsideRenderPassCommands->usesBufferForWrite(*bufferAccess.buffer));
6150
6151 mOutsideRenderPassCommands->bufferRead(this, bufferAccess.accessType, bufferAccess.stage,
6152 bufferAccess.buffer);
6153 }
6154
6155 for (const vk::CommandBufferBufferAccess &bufferAccess : access.getWriteBuffers())
6156 {
6157 ASSERT(!mRenderPassCommands->usesBuffer(*bufferAccess.buffer));
6158 ASSERT(!mOutsideRenderPassCommands->usesBuffer(*bufferAccess.buffer));
6159
6160 mOutsideRenderPassCommands->bufferWrite(this, bufferAccess.accessType, bufferAccess.stage,
6161 vk::AliasingMode::Disallowed, bufferAccess.buffer);
6162 }
6163
6164 return angle::Result::Continue;
6165 }
6166
flushCommandBuffersIfNecessary(const vk::CommandBufferAccess & access)6167 angle::Result ContextVk::flushCommandBuffersIfNecessary(const vk::CommandBufferAccess &access)
6168 {
6169 // Go over resources and decide whether the render pass needs to close, whether the outside
6170 // render pass commands need to be flushed, or neither. Note that closing the render pass
6171 // implies flushing the outside render pass as well, so if that needs to be done, we can close
6172 // the render pass and immediately return from this function. Otherwise, this function keeps
6173 // track of whether the outside render pass commands need to be closed, and if so, it will do
6174 // that once at the end.
6175
6176 // Read images only need to close the render pass if they need a layout transition.
6177 for (const vk::CommandBufferImageAccess &imageAccess : access.getReadImages())
6178 {
6179 // Note that different read methods are not compatible. A shader read uses a different
6180 // layout than a transfer read. So we cannot support simultaneous read usage as easily as
6181 // for Buffers. TODO: Don't close the render pass if the image was only used read-only in
6182 // the render pass. http://anglebug.com/4984
6183 if (IsRenderPassStartedAndUsesImage(*mRenderPassCommands, *imageAccess.image))
6184 {
6185 return flushCommandsAndEndRenderPass();
6186 }
6187 }
6188
6189 // Write images only need to close the render pass if they need a layout transition.
6190 for (const vk::CommandBufferImageWrite &imageWrite : access.getWriteImages())
6191 {
6192 if (IsRenderPassStartedAndUsesImage(*mRenderPassCommands, *imageWrite.access.image))
6193 {
6194 return flushCommandsAndEndRenderPass();
6195 }
6196 }
6197
6198 bool shouldCloseOutsideRenderPassCommands = false;
6199
6200 // Read buffers only need a new command buffer if previously used for write.
6201 for (const vk::CommandBufferBufferAccess &bufferAccess : access.getReadBuffers())
6202 {
6203 if (mRenderPassCommands->usesBufferForWrite(*bufferAccess.buffer))
6204 {
6205 return flushCommandsAndEndRenderPass();
6206 }
6207 else if (mOutsideRenderPassCommands->usesBufferForWrite(*bufferAccess.buffer))
6208 {
6209 shouldCloseOutsideRenderPassCommands = true;
6210 }
6211 }
6212
6213 // Write buffers always need a new command buffer if previously used.
6214 for (const vk::CommandBufferBufferAccess &bufferAccess : access.getWriteBuffers())
6215 {
6216 if (mRenderPassCommands->usesBuffer(*bufferAccess.buffer))
6217 {
6218 return flushCommandsAndEndRenderPass();
6219 }
6220 else if (mOutsideRenderPassCommands->usesBuffer(*bufferAccess.buffer))
6221 {
6222 shouldCloseOutsideRenderPassCommands = true;
6223 }
6224 }
6225
6226 if (shouldCloseOutsideRenderPassCommands)
6227 {
6228 return flushOutsideRenderPassCommands();
6229 }
6230
6231 return angle::Result::Continue;
6232 }
6233
endRenderPassIfComputeReadAfterTransformFeedbackWrite()6234 angle::Result ContextVk::endRenderPassIfComputeReadAfterTransformFeedbackWrite()
6235 {
6236 // Similar to flushCommandBuffersIfNecessary(), but using uniform buffers currently bound and
6237 // used by the current (compute) program. This is to handle read-after-write hazards where the
6238 // write originates from transform feedback.
6239 if (mCurrentTransformFeedbackBuffers.empty())
6240 {
6241 return angle::Result::Continue;
6242 }
6243
6244 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
6245 ASSERT(executable && executable->isCompute());
6246
6247 gl::ShaderMap<const gl::ProgramState *> programStates;
6248 mExecutable->fillProgramStateMap(this, &programStates);
6249
6250 for (const gl::ShaderType shaderType : executable->getLinkedShaderStages())
6251 {
6252 const gl::ProgramState *programState = programStates[shaderType];
6253 ASSERT(programState);
6254
6255 // Uniform buffers:
6256 const std::vector<gl::InterfaceBlock> &blocks = programState->getUniformBlocks();
6257
6258 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
6259 {
6260 const gl::InterfaceBlock &block = blocks[bufferIndex];
6261 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
6262 mState.getIndexedUniformBuffer(block.binding);
6263
6264 if (!block.isActive(shaderType) || bufferBinding.get() == nullptr)
6265 {
6266 continue;
6267 }
6268
6269 VkDeviceSize bufferOffset = 0;
6270 vk::BufferHelper &buffer =
6271 vk::GetImpl(bufferBinding.get())->getBufferAndOffset(&bufferOffset);
6272 if (mCurrentTransformFeedbackBuffers.contains(&buffer))
6273 {
6274 return flushCommandsAndEndRenderPass();
6275 }
6276 }
6277 }
6278
6279 return angle::Result::Continue;
6280 }
6281
endRenderPassIfComputeReadAfterAttachmentWrite()6282 angle::Result ContextVk::endRenderPassIfComputeReadAfterAttachmentWrite()
6283 {
6284 // Similar to flushCommandBuffersIfNecessary(), but using textures currently bound and used by
6285 // the current (compute) program. This is to handle read-after-write hazards where the write
6286 // originates from a framebuffer attachment.
6287 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
6288 ASSERT(executable && executable->isCompute() && executable->hasTextures());
6289
6290 const gl::ActiveTexturesCache &textures = mState.getActiveTexturesCache();
6291 const gl::ActiveTextureTypeArray &textureTypes = executable->getActiveSamplerTypes();
6292
6293 for (size_t textureUnit : executable->getActiveSamplersMask())
6294 {
6295 gl::Texture *texture = textures[textureUnit];
6296 gl::TextureType textureType = textureTypes[textureUnit];
6297
6298 if (texture == nullptr || textureType == gl::TextureType::Buffer)
6299 {
6300 continue;
6301 }
6302
6303 TextureVk *textureVk = vk::GetImpl(texture);
6304 ASSERT(textureVk != nullptr);
6305 vk::ImageHelper &image = textureVk->getImage();
6306
6307 if (IsRenderPassStartedAndUsesImage(*mRenderPassCommands, image))
6308 {
6309 return flushCommandsAndEndRenderPass();
6310 }
6311 }
6312
6313 return angle::Result::Continue;
6314 }
6315
6316 // Requires that trace is enabled to see the output, which is supported with is_debug=true
outputCumulativePerfCounters()6317 void ContextVk::outputCumulativePerfCounters()
6318 {
6319 if (!vk::kOutputCumulativePerfCounters)
6320 {
6321 return;
6322 }
6323
6324 INFO() << "Context Descriptor Set Allocations: ";
6325
6326 for (PipelineType pipelineType : angle::AllEnums<PipelineType>())
6327 {
6328 uint32_t count = mCumulativeContextPerfCounters.descriptorSetsAllocated[pipelineType];
6329 if (count > 0)
6330 {
6331 INFO() << " PipelineType " << ToUnderlying(pipelineType) << ": " << count;
6332 }
6333 }
6334 }
6335
getAndResetObjectPerfCounters()6336 ContextVkPerfCounters ContextVk::getAndResetObjectPerfCounters()
6337 {
6338 mCumulativeContextPerfCounters.descriptorSetsAllocated +=
6339 mContextPerfCounters.descriptorSetsAllocated;
6340
6341 ContextVkPerfCounters counters = mContextPerfCounters;
6342 mContextPerfCounters.descriptorSetsAllocated = {};
6343 return counters;
6344 }
6345 } // namespace rx
6346