1 //
2 // Copyright 2019 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 // OverlayVk.cpp:
7 // Implements the OverlayVk class.
8 //
9
10 #include "libANGLE/renderer/vulkan/OverlayVk.h"
11
12 #include "common/system_utils.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/Overlay_font_autogen.h"
15 #include "libANGLE/renderer/vulkan/ContextVk.h"
16
17 #include <numeric>
18
19 namespace rx
20 {
OverlayVk(const gl::OverlayState & state)21 OverlayVk::OverlayVk(const gl::OverlayState &state)
22 : OverlayImpl(state),
23 mSupportsSubgroupBallot(false),
24 mSupportsSubgroupArithmetic(false),
25 mRefreshCulledWidgets(false),
26 mSubgroupSize{},
27 mPresentImageExtent{}
28 {}
29 OverlayVk::~OverlayVk() = default;
30
init(const gl::Context * context,bool * successOut)31 angle::Result OverlayVk::init(const gl::Context *context, bool *successOut)
32 {
33 *successOut = false;
34
35 ContextVk *contextVk = vk::GetImpl(context);
36 RendererVk *rendererVk = contextVk->getRenderer();
37
38 const VkPhysicalDeviceSubgroupProperties &subgroupProperties =
39 rendererVk->getPhysicalDeviceSubgroupProperties();
40 uint32_t subgroupSize = subgroupProperties.subgroupSize;
41
42 // Currently, only subgroup sizes 32 and 64 are supported.
43 if (subgroupSize != 32 && subgroupSize != 64)
44 {
45 return angle::Result::Continue;
46 }
47
48 mSubgroupSize[0] = 8;
49 mSubgroupSize[1] = subgroupSize / 8;
50
51 constexpr VkSubgroupFeatureFlags kSubgroupBallotOperations =
52 VK_SUBGROUP_FEATURE_BASIC_BIT | VK_SUBGROUP_FEATURE_BALLOT_BIT;
53 constexpr VkSubgroupFeatureFlags kSubgroupArithmeticOperations =
54 VK_SUBGROUP_FEATURE_BASIC_BIT | VK_SUBGROUP_FEATURE_ARITHMETIC_BIT;
55
56 // If not all operations used in the shaders are supported, disable the overlay.
57 if ((subgroupProperties.supportedOperations & kSubgroupBallotOperations) ==
58 kSubgroupBallotOperations)
59 {
60 mSupportsSubgroupBallot = true;
61 }
62 else if ((subgroupProperties.supportedOperations & kSubgroupArithmeticOperations) ==
63 kSubgroupArithmeticOperations)
64 {
65 mSupportsSubgroupArithmetic = true;
66 }
67
68 ANGLE_TRY(createFont(contextVk));
69
70 mRefreshCulledWidgets = true;
71
72 ANGLE_TRY(contextVk->flushImpl(nullptr));
73 *successOut = true;
74 return angle::Result::Continue;
75 }
76
onDestroy(const gl::Context * context)77 void OverlayVk::onDestroy(const gl::Context *context)
78 {
79 RendererVk *renderer = vk::GetImpl(context)->getRenderer();
80 VkDevice device = renderer->getDevice();
81
82 mCulledWidgets.destroy(renderer);
83 mCulledWidgetsView.destroy(device);
84
85 mFontImage.destroy(renderer);
86 mFontImageView.destroy(device);
87 }
88
createFont(ContextVk * contextVk)89 angle::Result OverlayVk::createFont(ContextVk *contextVk)
90 {
91 RendererVk *renderer = contextVk->getRenderer();
92
93 // Create a buffer to stage font data upload.
94 VkBufferCreateInfo bufferCreateInfo = {};
95 bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
96 bufferCreateInfo.size =
97 gl::overlay::kFontCount * gl::overlay::kFontImageWidth * gl::overlay::kFontImageHeight;
98 bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
99 bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
100
101 vk::RendererScoped<vk::BufferHelper> fontDataBuffer(renderer);
102
103 ANGLE_TRY(fontDataBuffer.get().init(contextVk, bufferCreateInfo,
104 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
105
106 uint8_t *fontData;
107 ANGLE_TRY(fontDataBuffer.get().map(contextVk, &fontData));
108
109 mState.initFontData(fontData);
110
111 ANGLE_TRY(fontDataBuffer.get().flush(renderer, 0, fontDataBuffer.get().getSize()));
112 fontDataBuffer.get().unmap(renderer);
113
114 // Don't use robust resource init for overlay widgets.
115 bool useRobustInit = false;
116
117 // Create the font image.
118 ANGLE_TRY(
119 mFontImage.init(contextVk, gl::TextureType::_2D,
120 VkExtent3D{gl::overlay::kFontImageWidth, gl::overlay::kFontImageHeight, 1},
121 renderer->getFormat(angle::FormatID::R8_UNORM), 1,
122 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
123 gl::LevelIndex(0), 1, gl::overlay::kFontCount, useRobustInit, false));
124 ANGLE_TRY(mFontImage.initMemory(contextVk, false, renderer->getMemoryProperties(),
125 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
126 ANGLE_TRY(mFontImage.initImageView(contextVk, gl::TextureType::_2DArray,
127 VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
128 &mFontImageView, vk::LevelIndex(0), 1));
129
130 // Copy font data from staging buffer.
131 vk::CommandBufferAccess access;
132 access.onBufferTransferRead(&fontDataBuffer.get());
133 access.onImageTransferWrite(gl::LevelIndex(0), 1, 0, gl::overlay::kFontCount,
134 VK_IMAGE_ASPECT_COLOR_BIT, &mFontImage);
135 vk::CommandBuffer *fontDataUpload;
136 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &fontDataUpload));
137
138 VkBufferImageCopy copy = {};
139 copy.bufferRowLength = gl::overlay::kFontImageWidth;
140 copy.bufferImageHeight = gl::overlay::kFontImageHeight;
141 copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
142 copy.imageSubresource.layerCount = gl::overlay::kFontCount;
143 copy.imageExtent.width = gl::overlay::kFontImageWidth;
144 copy.imageExtent.height = gl::overlay::kFontImageHeight;
145 copy.imageExtent.depth = 1;
146
147 fontDataUpload->copyBufferToImage(fontDataBuffer.get().getBuffer().getHandle(),
148 mFontImage.getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
149 1, ©);
150
151 return angle::Result::Continue;
152 }
153
cullWidgets(ContextVk * contextVk)154 angle::Result OverlayVk::cullWidgets(ContextVk *contextVk)
155 {
156 RendererVk *renderer = contextVk->getRenderer();
157
158 // Release old culledWidgets image
159 mCulledWidgets.releaseImageFromShareContexts(renderer, contextVk);
160 contextVk->addGarbage(&mCulledWidgetsView);
161
162 // Create a buffer to contain coordinates of enabled text and graph widgets. This buffer will
163 // be used to perform tiled culling and can be discarded immediately after.
164 VkBufferCreateInfo bufferCreateInfo = {};
165 bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
166 bufferCreateInfo.size = mState.getWidgetCoordinatesBufferSize();
167 bufferCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
168 bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
169
170 vk::RendererScoped<vk::BufferHelper> enabledWidgetsBuffer(renderer);
171
172 ANGLE_TRY(enabledWidgetsBuffer.get().init(contextVk, bufferCreateInfo,
173 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
174
175 // Fill the buffer with coordinate information from enabled widgets.
176 uint8_t *enabledWidgets;
177 ANGLE_TRY(enabledWidgetsBuffer.get().map(contextVk, &enabledWidgets));
178
179 gl::Extents presentImageExtents(mPresentImageExtent.width, mPresentImageExtent.height, 1);
180 mState.fillEnabledWidgetCoordinates(presentImageExtents, enabledWidgets);
181
182 ANGLE_TRY(enabledWidgetsBuffer.get().flush(renderer, 0, enabledWidgetsBuffer.get().getSize()));
183 enabledWidgetsBuffer.get().unmap(renderer);
184
185 // Allocate mCulledWidget and its view.
186 VkExtent3D culledWidgetsExtent = {
187 UnsignedCeilDivide(mPresentImageExtent.width, mSubgroupSize[0]),
188 UnsignedCeilDivide(mPresentImageExtent.height, mSubgroupSize[1]), 1};
189
190 // Don't use robust resource init for overlay widgets.
191 bool useRobustInit = false;
192
193 ANGLE_TRY(mCulledWidgets.init(contextVk, gl::TextureType::_2D, culledWidgetsExtent,
194 renderer->getFormat(angle::FormatID::R32G32_UINT), 1,
195 VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
196 gl::LevelIndex(0), 1, 1, useRobustInit, false));
197 ANGLE_TRY(mCulledWidgets.initMemory(contextVk, false, renderer->getMemoryProperties(),
198 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
199 ANGLE_TRY(mCulledWidgets.initImageView(contextVk, gl::TextureType::_2D,
200 VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
201 &mCulledWidgetsView, vk::LevelIndex(0), 1));
202
203 UtilsVk::OverlayCullParameters params;
204 params.subgroupSize[0] = mSubgroupSize[0];
205 params.subgroupSize[1] = mSubgroupSize[1];
206 params.supportsSubgroupBallot = mSupportsSubgroupBallot;
207 params.supportsSubgroupArithmetic = mSupportsSubgroupArithmetic;
208
209 return contextVk->getUtils().cullOverlayWidgets(contextVk, &enabledWidgetsBuffer.get(),
210 &mCulledWidgets, &mCulledWidgetsView, params);
211 }
212
onPresent(ContextVk * contextVk,vk::ImageHelper * imageToPresent,const vk::ImageView * imageToPresentView,bool is90DegreeRotation)213 angle::Result OverlayVk::onPresent(ContextVk *contextVk,
214 vk::ImageHelper *imageToPresent,
215 const vk::ImageView *imageToPresentView,
216 bool is90DegreeRotation)
217 {
218 if (mState.getEnabledWidgetCount() == 0)
219 {
220 return angle::Result::Continue;
221 }
222
223 RendererVk *renderer = contextVk->getRenderer();
224
225 // If the swapchain image doesn't support storage image, we can't output to it.
226 VkFormatFeatureFlags featureBits = renderer->getImageFormatFeatureBits(
227 imageToPresent->getFormat().actualImageFormatID, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT);
228 if ((featureBits & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0)
229 {
230 return angle::Result::Continue;
231 }
232
233 const VkExtent3D &imageExtent = imageToPresent->getExtents();
234
235 mRefreshCulledWidgets = mRefreshCulledWidgets ||
236 mPresentImageExtent.width != imageExtent.width ||
237 mPresentImageExtent.height != imageExtent.height;
238
239 if (mRefreshCulledWidgets)
240 {
241 mPresentImageExtent.width = imageExtent.width;
242 mPresentImageExtent.height = imageExtent.height;
243
244 ANGLE_TRY(cullWidgets(contextVk));
245
246 mRefreshCulledWidgets = false;
247 }
248
249 vk::RendererScoped<vk::BufferHelper> textDataBuffer(renderer);
250 vk::RendererScoped<vk::BufferHelper> graphDataBuffer(renderer);
251
252 VkBufferCreateInfo textBufferCreateInfo = {};
253 textBufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
254 textBufferCreateInfo.size = mState.getTextWidgetsBufferSize();
255 textBufferCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
256 textBufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
257
258 VkBufferCreateInfo graphBufferCreateInfo = textBufferCreateInfo;
259 graphBufferCreateInfo.size = mState.getGraphWidgetsBufferSize();
260
261 ANGLE_TRY(textDataBuffer.get().init(contextVk, textBufferCreateInfo,
262 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
263 ANGLE_TRY(graphDataBuffer.get().init(contextVk, graphBufferCreateInfo,
264 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
265
266 uint8_t *textData;
267 uint8_t *graphData;
268 ANGLE_TRY(textDataBuffer.get().map(contextVk, &textData));
269 ANGLE_TRY(graphDataBuffer.get().map(contextVk, &graphData));
270
271 gl::Extents presentImageExtents(mPresentImageExtent.width, mPresentImageExtent.height, 1);
272 mState.fillWidgetData(presentImageExtents, textData, graphData);
273
274 ANGLE_TRY(textDataBuffer.get().flush(renderer, 0, textDataBuffer.get().getSize()));
275 ANGLE_TRY(graphDataBuffer.get().flush(renderer, 0, graphDataBuffer.get().getSize()));
276 textDataBuffer.get().unmap(renderer);
277 graphDataBuffer.get().unmap(renderer);
278
279 UtilsVk::OverlayDrawParameters params;
280 params.subgroupSize[0] = mSubgroupSize[0];
281 params.subgroupSize[1] = mSubgroupSize[1];
282 params.rotateXY = is90DegreeRotation;
283
284 return contextVk->getUtils().drawOverlay(
285 contextVk, &textDataBuffer.get(), &graphDataBuffer.get(), &mFontImage, &mFontImageView,
286 &mCulledWidgets, &mCulledWidgetsView, imageToPresent, imageToPresentView, params);
287 }
288
289 } // namespace rx
290