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