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 // RenderTargetVk:
7 // Wrapper around a Vulkan renderable resource, using an ImageView.
8 //
9
10 #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
11
12 #include "libANGLE/renderer/vulkan/ContextVk.h"
13 #include "libANGLE/renderer/vulkan/ResourceVk.h"
14 #include "libANGLE/renderer/vulkan/TextureVk.h"
15 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
16 #include "libANGLE/renderer/vulkan/vk_helpers.h"
17
18 namespace rx
19 {
20
RenderTargetVk()21 RenderTargetVk::RenderTargetVk()
22 {
23 reset();
24 }
25
~RenderTargetVk()26 RenderTargetVk::~RenderTargetVk() {}
27
RenderTargetVk(RenderTargetVk && other)28 RenderTargetVk::RenderTargetVk(RenderTargetVk &&other)
29 : mImage(other.mImage),
30 mImageViews(other.mImageViews),
31 mResolveImage(other.mResolveImage),
32 mResolveImageViews(other.mResolveImageViews),
33 mLevelIndexGL(other.mLevelIndexGL),
34 mLayerIndex(other.mLayerIndex),
35 mLayerCount(other.mLayerCount)
36 {
37 other.reset();
38 }
39
init(vk::ImageHelper * image,vk::ImageViewHelper * imageViews,vk::ImageHelper * resolveImage,vk::ImageViewHelper * resolveImageViews,gl::LevelIndex levelIndexGL,uint32_t layerIndex,uint32_t layerCount,RenderTargetTransience transience)40 void RenderTargetVk::init(vk::ImageHelper *image,
41 vk::ImageViewHelper *imageViews,
42 vk::ImageHelper *resolveImage,
43 vk::ImageViewHelper *resolveImageViews,
44 gl::LevelIndex levelIndexGL,
45 uint32_t layerIndex,
46 uint32_t layerCount,
47 RenderTargetTransience transience)
48 {
49 mImage = image;
50 mImageViews = imageViews;
51 mResolveImage = resolveImage;
52 mResolveImageViews = resolveImageViews;
53 mLevelIndexGL = levelIndexGL;
54 mLayerIndex = layerIndex;
55 mLayerCount = layerCount;
56
57 mTransience = transience;
58 }
59
reset()60 void RenderTargetVk::reset()
61 {
62 mImage = nullptr;
63 mImageViews = nullptr;
64 mResolveImage = nullptr;
65 mResolveImageViews = nullptr;
66 mLevelIndexGL = gl::LevelIndex(0);
67 mLayerIndex = 0;
68 mLayerCount = 0;
69 }
70
getSubresourceSerialImpl(vk::ImageViewHelper * imageViews) const71 vk::ImageOrBufferViewSubresourceSerial RenderTargetVk::getSubresourceSerialImpl(
72 vk::ImageViewHelper *imageViews) const
73 {
74 ASSERT(imageViews);
75 ASSERT(mLayerIndex < std::numeric_limits<uint16_t>::max());
76 ASSERT(mLevelIndexGL.get() < std::numeric_limits<uint16_t>::max());
77
78 vk::ImageOrBufferViewSubresourceSerial imageViewSerial = imageViews->getSubresourceSerial(
79 mLevelIndexGL, 1, mLayerIndex, vk::GetLayerMode(*mImage, mLayerCount),
80 vk::SrgbDecodeMode::SkipDecode, gl::SrgbOverride::Default);
81 return imageViewSerial;
82 }
83
getDrawSubresourceSerial() const84 vk::ImageOrBufferViewSubresourceSerial RenderTargetVk::getDrawSubresourceSerial() const
85 {
86 return getSubresourceSerialImpl(mImageViews);
87 }
88
getResolveSubresourceSerial() const89 vk::ImageOrBufferViewSubresourceSerial RenderTargetVk::getResolveSubresourceSerial() const
90 {
91 return getSubresourceSerialImpl(mResolveImageViews);
92 }
93
onColorDraw(ContextVk * contextVk,uint32_t framebufferLayerCount,vk::PackedAttachmentIndex packedAttachmentIndex)94 void RenderTargetVk::onColorDraw(ContextVk *contextVk,
95 uint32_t framebufferLayerCount,
96 vk::PackedAttachmentIndex packedAttachmentIndex)
97 {
98 ASSERT(!mImage->getFormat().actualImageFormat().hasDepthOrStencilBits());
99 ASSERT(framebufferLayerCount <= mLayerCount);
100
101 contextVk->onColorDraw(mImage, mResolveImage, packedAttachmentIndex);
102 mImage->onWrite(mLevelIndexGL, 1, mLayerIndex, framebufferLayerCount,
103 VK_IMAGE_ASPECT_COLOR_BIT);
104 if (mResolveImage)
105 {
106 // Multisampled render to texture framebuffers cannot be layered.
107 ASSERT(framebufferLayerCount == 1);
108 mResolveImage->onWrite(mLevelIndexGL, 1, mLayerIndex, framebufferLayerCount,
109 VK_IMAGE_ASPECT_COLOR_BIT);
110 }
111 retainImageViews(contextVk);
112 }
113
onColorResolve(ContextVk * contextVk,uint32_t framebufferLayerCount)114 void RenderTargetVk::onColorResolve(ContextVk *contextVk, uint32_t framebufferLayerCount)
115 {
116 ASSERT(!mImage->getFormat().actualImageFormat().hasDepthOrStencilBits());
117 ASSERT(framebufferLayerCount <= mLayerCount);
118 ASSERT(mResolveImage == nullptr);
119
120 contextVk->onImageRenderPassWrite(mLevelIndexGL, mLayerIndex, framebufferLayerCount,
121 VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment,
122 mImage);
123 retainImageViews(contextVk);
124 }
125
onDepthStencilDraw(ContextVk * contextVk,uint32_t framebufferLayerCount)126 void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk, uint32_t framebufferLayerCount)
127 {
128 const angle::Format &format = mImage->getFormat().actualImageFormat();
129 ASSERT(format.hasDepthOrStencilBits());
130 ASSERT(framebufferLayerCount <= mLayerCount);
131
132 contextVk->onDepthStencilDraw(mLevelIndexGL, mLayerIndex, framebufferLayerCount, mImage,
133 mResolveImage);
134 retainImageViews(contextVk);
135 }
136
getImageForRenderPass()137 vk::ImageHelper &RenderTargetVk::getImageForRenderPass()
138 {
139 ASSERT(mImage && mImage->valid());
140 return *mImage;
141 }
142
getImageForRenderPass() const143 const vk::ImageHelper &RenderTargetVk::getImageForRenderPass() const
144 {
145 ASSERT(mImage && mImage->valid());
146 return *mImage;
147 }
148
getResolveImageForRenderPass()149 vk::ImageHelper &RenderTargetVk::getResolveImageForRenderPass()
150 {
151 ASSERT(mResolveImage && mResolveImage->valid());
152 return *mResolveImage;
153 }
154
getResolveImageForRenderPass() const155 const vk::ImageHelper &RenderTargetVk::getResolveImageForRenderPass() const
156 {
157 ASSERT(mResolveImage && mResolveImage->valid());
158 return *mResolveImage;
159 }
160
getImageViewImpl(ContextVk * contextVk,const vk::ImageHelper & image,gl::SrgbWriteControlMode mode,vk::ImageViewHelper * imageViews,const vk::ImageView ** imageViewOut) const161 angle::Result RenderTargetVk::getImageViewImpl(ContextVk *contextVk,
162 const vk::ImageHelper &image,
163 gl::SrgbWriteControlMode mode,
164 vk::ImageViewHelper *imageViews,
165 const vk::ImageView **imageViewOut) const
166 {
167 ASSERT(image.valid() && imageViews);
168 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
169 if (mLayerCount == 1)
170 {
171 return imageViews->getLevelLayerDrawImageView(contextVk, image, levelVk, mLayerIndex, mode,
172 imageViewOut);
173 }
174
175 // Layered render targets view the whole level or a handful of layers in case of multiview.
176 return imageViews->getLevelDrawImageView(contextVk, image, levelVk, mLayerIndex, mLayerCount,
177 mode, imageViewOut);
178 }
179
getImageView(ContextVk * contextVk,const vk::ImageView ** imageViewOut) const180 angle::Result RenderTargetVk::getImageView(ContextVk *contextVk,
181 const vk::ImageView **imageViewOut) const
182 {
183 ASSERT(mImage);
184 return getImageViewImpl(contextVk, *mImage, gl::SrgbWriteControlMode::Default, mImageViews,
185 imageViewOut);
186 }
187
getImageViewWithColorspace(ContextVk * contextVk,gl::SrgbWriteControlMode mode,const vk::ImageView ** imageViewOut) const188 angle::Result RenderTargetVk::getImageViewWithColorspace(ContextVk *contextVk,
189 gl::SrgbWriteControlMode mode,
190 const vk::ImageView **imageViewOut) const
191 {
192 ASSERT(mImage);
193 return getImageViewImpl(contextVk, *mImage, mode, mImageViews, imageViewOut);
194 }
195
getResolveImageView(ContextVk * contextVk,const vk::ImageView ** imageViewOut) const196 angle::Result RenderTargetVk::getResolveImageView(ContextVk *contextVk,
197 const vk::ImageView **imageViewOut) const
198 {
199 ASSERT(mResolveImage);
200 return getImageViewImpl(contextVk, *mResolveImage, gl::SrgbWriteControlMode::Default,
201 mResolveImageViews, imageViewOut);
202 }
203
isResolveImageOwnerOfData() const204 bool RenderTargetVk::isResolveImageOwnerOfData() const
205 {
206 // If there's a resolve attachment and the image itself is transient, it's the resolve
207 // attachment that owns the data, so all non-render-pass accesses to the render target data
208 // should go through the resolve attachment.
209 return isImageTransient();
210 }
211
getOwnerOfData() const212 vk::ImageHelper *RenderTargetVk::getOwnerOfData() const
213 {
214 return isResolveImageOwnerOfData() ? mResolveImage : mImage;
215 }
216
getAndRetainCopyImageView(ContextVk * contextVk,const vk::ImageView ** imageViewOut) const217 angle::Result RenderTargetVk::getAndRetainCopyImageView(ContextVk *contextVk,
218 const vk::ImageView **imageViewOut) const
219 {
220 retainImageViews(contextVk);
221
222 const vk::ImageViewHelper *imageViews =
223 isResolveImageOwnerOfData() ? mResolveImageViews : mImageViews;
224
225 // If the source of render target is a texture or renderbuffer, this will always be valid. This
226 // is also where 3D or 2DArray images could be the source of the render target.
227 if (imageViews->hasCopyImageView())
228 {
229 *imageViewOut = &imageViews->getCopyImageView();
230 return angle::Result::Continue;
231 }
232
233 // Otherwise, this must come from the surface, in which case the image is 2D, so the image view
234 // used to draw is just as good for fetching. If resolve attachment is present, fetching is
235 // done from that.
236 return isResolveImageOwnerOfData() ? getResolveImageView(contextVk, imageViewOut)
237 : getImageView(contextVk, imageViewOut);
238 }
239
getImageFormat() const240 const vk::Format &RenderTargetVk::getImageFormat() const
241 {
242 ASSERT(mImage && mImage->valid());
243 return mImage->getFormat();
244 }
245
getExtents() const246 gl::Extents RenderTargetVk::getExtents() const
247 {
248 ASSERT(mImage && mImage->valid());
249 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
250 return mImage->getLevelExtents2D(levelVk);
251 }
252
getRotatedExtents() const253 gl::Extents RenderTargetVk::getRotatedExtents() const
254 {
255 ASSERT(mImage && mImage->valid());
256 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
257 return mImage->getRotatedLevelExtents2D(levelVk);
258 }
259
updateSwapchainImage(vk::ImageHelper * image,vk::ImageViewHelper * imageViews,vk::ImageHelper * resolveImage,vk::ImageViewHelper * resolveImageViews)260 void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image,
261 vk::ImageViewHelper *imageViews,
262 vk::ImageHelper *resolveImage,
263 vk::ImageViewHelper *resolveImageViews)
264 {
265 ASSERT(image && image->valid() && imageViews);
266 mImage = image;
267 mImageViews = imageViews;
268 mResolveImage = resolveImage;
269 mResolveImageViews = resolveImageViews;
270 }
271
getImageForCopy() const272 vk::ImageHelper &RenderTargetVk::getImageForCopy() const
273 {
274 ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
275 return *getOwnerOfData();
276 }
277
getImageForWrite() const278 vk::ImageHelper &RenderTargetVk::getImageForWrite() const
279 {
280 ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
281 return *getOwnerOfData();
282 }
283
flushStagedUpdates(ContextVk * contextVk,vk::ClearValuesArray * deferredClears,uint32_t deferredClearIndex,uint32_t framebufferLayerCount)284 angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk,
285 vk::ClearValuesArray *deferredClears,
286 uint32_t deferredClearIndex,
287 uint32_t framebufferLayerCount)
288 {
289 ASSERT(mImage->valid() && (!isResolveImageOwnerOfData() || mResolveImage->valid()));
290 ASSERT(framebufferLayerCount != 0);
291
292 // It's impossible to defer clears to slices of a 3D images, as the clear applies to all the
293 // slices, while deferred clears only clear a single slice (where the framebuffer is attached).
294 // Additionally, the layer index for 3D textures is always zero according to Vulkan.
295 uint32_t layerIndex = mLayerIndex;
296 if (mImage->getType() == VK_IMAGE_TYPE_3D)
297 {
298 layerIndex = 0;
299 deferredClears = nullptr;
300 deferredClearIndex = 0;
301 }
302
303 vk::ImageHelper *image = getOwnerOfData();
304
305 // All updates should be staged on the image that owns the data as the source of truth. With
306 // multisampled-render-to-texture framebuffers, that is the resolve image. In that case, even
307 // though deferred clears set the loadOp of the transient multisampled image, the clears
308 // themselves are staged on the resolve image. The |flushSingleSubresourceStagedUpdates| call
309 // below will either flush all staged updates to the resolve image, or if the only staged update
310 // is a clear, it will accumulate it in the |deferredClears| array. Later, when the render pass
311 // is started, the deferred clears are applied to the transient multisampled image.
312 ASSERT(!isResolveImageOwnerOfData() ||
313 !mImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
314 ASSERT(isResolveImageOwnerOfData() || mResolveImage == nullptr ||
315 !mResolveImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
316
317 if (!image->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, framebufferLayerCount))
318 {
319 return angle::Result::Continue;
320 }
321
322 return image->flushSingleSubresourceStagedUpdates(contextVk, mLevelIndexGL, layerIndex,
323 framebufferLayerCount, deferredClears,
324 deferredClearIndex);
325 }
326
retainImageViews(ContextVk * contextVk) const327 void RenderTargetVk::retainImageViews(ContextVk *contextVk) const
328 {
329 mImageViews->retain(&contextVk->getResourceUseList());
330 if (mResolveImageViews)
331 {
332 mResolveImageViews->retain(&contextVk->getResourceUseList());
333 }
334 }
335
hasDefinedContent() const336 bool RenderTargetVk::hasDefinedContent() const
337 {
338 vk::ImageHelper *image = getOwnerOfData();
339 return image->hasSubresourceDefinedContent(mLevelIndexGL, mLayerIndex, mLayerCount);
340 }
341
hasDefinedStencilContent() const342 bool RenderTargetVk::hasDefinedStencilContent() const
343 {
344 vk::ImageHelper *image = getOwnerOfData();
345 return image->hasSubresourceDefinedStencilContent(mLevelIndexGL, mLayerIndex, mLayerCount);
346 }
347
invalidateEntireContent(ContextVk * contextVk)348 void RenderTargetVk::invalidateEntireContent(ContextVk *contextVk)
349 {
350 vk::ImageHelper *image = getOwnerOfData();
351 image->invalidateSubresourceContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount);
352 }
353
invalidateEntireStencilContent(ContextVk * contextVk)354 void RenderTargetVk::invalidateEntireStencilContent(ContextVk *contextVk)
355 {
356 vk::ImageHelper *image = getOwnerOfData();
357 image->invalidateSubresourceStencilContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount);
358 }
359
restoreEntireContent()360 void RenderTargetVk::restoreEntireContent()
361 {
362 vk::ImageHelper *image = getOwnerOfData();
363 image->restoreSubresourceContent(mLevelIndexGL, mLayerIndex, mLayerCount);
364 }
365
restoreEntireStencilContent()366 void RenderTargetVk::restoreEntireStencilContent()
367 {
368 vk::ImageHelper *image = getOwnerOfData();
369 image->restoreSubresourceStencilContent(mLevelIndexGL, mLayerIndex, mLayerCount);
370 }
371
getImageIndexForClear(uint32_t layerCount) const372 gl::ImageIndex RenderTargetVk::getImageIndexForClear(uint32_t layerCount) const
373 {
374 // Determine the GL type from the Vk Image properties.
375 if (mImage->getType() == VK_IMAGE_TYPE_3D || mImage->getLayerCount() > 1)
376 {
377 // This is used for the sake of staging clears. The depth slices of the 3D image are
378 // threated as layers for this purpose.
379 //
380 // We also don't need to distinguish 2D array and cube.
381 return gl::ImageIndex::Make2DArrayRange(mLevelIndexGL.get(), mLayerIndex, layerCount);
382 }
383
384 ASSERT(mLayerIndex == 0);
385 ASSERT(mLayerCount == 1);
386 ASSERT(layerCount == 1);
387 return gl::ImageIndex::Make2D(mLevelIndexGL.get());
388 }
389 } // namespace rx
390