• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &copy);
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