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/TextureVk.h"
14 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
15 #include "libANGLE/renderer/vulkan/vk_helpers.h"
16 #include "libANGLE/renderer/vulkan/vk_resource.h"
17
18 namespace rx
19 {
20
RenderTargetVk()21 RenderTargetVk::RenderTargetVk()
22 {
23 reset();
24 }
25
~RenderTargetVk()26 RenderTargetVk::~RenderTargetVk()
27 {
28 ASSERT(mFramebufferCacheManager.empty());
29 }
30
RenderTargetVk(RenderTargetVk && other)31 RenderTargetVk::RenderTargetVk(RenderTargetVk &&other)
32 : mImage(other.mImage),
33 mImageViews(other.mImageViews),
34 mResolveImage(other.mResolveImage),
35 mResolveImageViews(other.mResolveImageViews),
36 mImageSiblingSerial(other.mImageSiblingSerial),
37 mLevelIndexGL(other.mLevelIndexGL),
38 mLayerIndex(other.mLayerIndex),
39 mLayerCount(other.mLayerCount),
40 mFramebufferCacheManager(other.mFramebufferCacheManager)
41 {
42 other.reset();
43 }
44
init(vk::ImageHelper * image,vk::ImageViewHelper * imageViews,vk::ImageHelper * resolveImage,vk::ImageViewHelper * resolveImageViews,UniqueSerial imageSiblingSerial,gl::LevelIndex levelIndexGL,uint32_t layerIndex,uint32_t layerCount,RenderTargetTransience transience)45 void RenderTargetVk::init(vk::ImageHelper *image,
46 vk::ImageViewHelper *imageViews,
47 vk::ImageHelper *resolveImage,
48 vk::ImageViewHelper *resolveImageViews,
49 UniqueSerial imageSiblingSerial,
50 gl::LevelIndex levelIndexGL,
51 uint32_t layerIndex,
52 uint32_t layerCount,
53 RenderTargetTransience transience)
54 {
55 mImage = image;
56 mImageViews = imageViews;
57 mResolveImage = resolveImage;
58 mResolveImageViews = resolveImageViews;
59 mImageSiblingSerial = imageSiblingSerial;
60 mLevelIndexGL = levelIndexGL;
61 mLayerIndex = layerIndex;
62 mLayerCount = layerCount;
63
64 mTransience = transience;
65 }
66
invalidateImageAndViews()67 void RenderTargetVk::invalidateImageAndViews()
68 {
69 mImage = nullptr;
70 mImageViews = nullptr;
71 mResolveImage = nullptr;
72 mResolveImageViews = nullptr;
73 }
74
reset()75 void RenderTargetVk::reset()
76 {
77 invalidateImageAndViews();
78 mImageSiblingSerial = {};
79 mLevelIndexGL = gl::LevelIndex(0);
80 mLayerIndex = 0;
81 mLayerCount = 0;
82 }
83
getSubresourceSerialImpl(vk::ImageViewHelper * imageViews) const84 vk::ImageOrBufferViewSubresourceSerial RenderTargetVk::getSubresourceSerialImpl(
85 vk::ImageViewHelper *imageViews) const
86 {
87 ASSERT(imageViews);
88 ASSERT(mLayerIndex < std::numeric_limits<uint16_t>::max());
89 ASSERT(mLevelIndexGL.get() < std::numeric_limits<uint16_t>::max());
90
91 vk::LayerMode layerMode = vk::GetLayerMode(*mImage, mLayerCount);
92 vk::ImageOrBufferViewSubresourceSerial imageViewSerial =
93 imageViews->getSubresourceSerial(mLevelIndexGL, 1, mLayerIndex, layerMode);
94 return imageViewSerial;
95 }
96
getDrawSubresourceSerial() const97 vk::ImageOrBufferViewSubresourceSerial RenderTargetVk::getDrawSubresourceSerial() const
98 {
99 return getSubresourceSerialImpl(mImageViews);
100 }
101
getResolveSubresourceSerial() const102 vk::ImageOrBufferViewSubresourceSerial RenderTargetVk::getResolveSubresourceSerial() const
103 {
104 return getSubresourceSerialImpl(mResolveImageViews);
105 }
106
onColorDraw(ContextVk * contextVk,uint32_t framebufferLayerCount,vk::PackedAttachmentIndex packedAttachmentIndex)107 void RenderTargetVk::onColorDraw(ContextVk *contextVk,
108 uint32_t framebufferLayerCount,
109 vk::PackedAttachmentIndex packedAttachmentIndex)
110 {
111 ASSERT(!mImage->getActualFormat().hasDepthOrStencilBits());
112 ASSERT(framebufferLayerCount <= mLayerCount);
113
114 contextVk->onColorDraw(mLevelIndexGL, mLayerIndex, framebufferLayerCount, mImage, mResolveImage,
115 mImageSiblingSerial, packedAttachmentIndex);
116
117 // Multisampled render to texture framebuffers cannot be layered.
118 ASSERT(mResolveImage == nullptr || framebufferLayerCount == 1);
119 }
120
onColorResolve(ContextVk * contextVk,uint32_t framebufferLayerCount,size_t readColorIndexGL,const vk::ImageView & view)121 void RenderTargetVk::onColorResolve(ContextVk *contextVk,
122 uint32_t framebufferLayerCount,
123 size_t readColorIndexGL,
124 const vk::ImageView &view)
125 {
126 ASSERT(!mImage->getActualFormat().hasDepthOrStencilBits());
127 ASSERT(framebufferLayerCount <= mLayerCount);
128 ASSERT(mResolveImage == nullptr);
129
130 // The currently open render pass is from the read framebuffer. This is the draw framebuffer's
131 // render target. Ask the context to add this image as the resolve attachment to the read
132 // framebuffer's render pass, at the given color index.
133 contextVk->onColorResolve(mLevelIndexGL, mLayerIndex, framebufferLayerCount, mImage,
134 view.getHandle(), mImageSiblingSerial, readColorIndexGL);
135 }
136
onDepthStencilDraw(ContextVk * contextVk,uint32_t framebufferLayerCount)137 void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk, uint32_t framebufferLayerCount)
138 {
139 const angle::Format &format = mImage->getActualFormat();
140 ASSERT(format.hasDepthOrStencilBits());
141 ASSERT(framebufferLayerCount <= mLayerCount);
142
143 contextVk->onDepthStencilDraw(mLevelIndexGL, mLayerIndex, framebufferLayerCount, mImage,
144 mResolveImage, mImageSiblingSerial);
145 }
146
onDepthStencilResolve(ContextVk * contextVk,uint32_t framebufferLayerCount,VkImageAspectFlags aspects,const vk::ImageView & view)147 void RenderTargetVk::onDepthStencilResolve(ContextVk *contextVk,
148 uint32_t framebufferLayerCount,
149 VkImageAspectFlags aspects,
150 const vk::ImageView &view)
151 {
152 ASSERT(mImage->getActualFormat().hasDepthOrStencilBits());
153 ASSERT(framebufferLayerCount <= mLayerCount);
154 ASSERT(mResolveImage == nullptr);
155
156 contextVk->onDepthStencilResolve(mLevelIndexGL, mLayerIndex, framebufferLayerCount, aspects,
157 mImage, view.getHandle(), mImageSiblingSerial);
158 }
159
getImageForRenderPass()160 vk::ImageHelper &RenderTargetVk::getImageForRenderPass()
161 {
162 ASSERT(mImage && mImage->valid());
163 return *mImage;
164 }
165
getImageForRenderPass() const166 const vk::ImageHelper &RenderTargetVk::getImageForRenderPass() const
167 {
168 ASSERT(mImage && mImage->valid());
169 return *mImage;
170 }
171
getResolveImageForRenderPass()172 vk::ImageHelper &RenderTargetVk::getResolveImageForRenderPass()
173 {
174 ASSERT(mResolveImage && mResolveImage->valid());
175 return *mResolveImage;
176 }
177
getResolveImageForRenderPass() const178 const vk::ImageHelper &RenderTargetVk::getResolveImageForRenderPass() const
179 {
180 ASSERT(mResolveImage && mResolveImage->valid());
181 return *mResolveImage;
182 }
183
getImageViewImpl(vk::Context * context,const vk::ImageHelper & image,vk::ImageViewHelper * imageViews,const vk::ImageView ** imageViewOut) const184 angle::Result RenderTargetVk::getImageViewImpl(vk::Context *context,
185 const vk::ImageHelper &image,
186 vk::ImageViewHelper *imageViews,
187 const vk::ImageView **imageViewOut) const
188 {
189 ASSERT(image.valid() && imageViews);
190 vk::LevelIndex levelVk = image.toVkLevel(getLevelIndexForImage(image));
191 if (mLayerCount == 1)
192 {
193 return imageViews->getLevelLayerDrawImageView(context, image, levelVk, mLayerIndex,
194 imageViewOut);
195 }
196
197 // Layered render targets view the whole level or a handful of layers in case of multiview.
198 return imageViews->getLevelDrawImageView(context, image, levelVk, mLayerIndex, mLayerCount,
199 imageViewOut);
200 }
201
getImageView(vk::Context * context,const vk::ImageView ** imageViewOut) const202 angle::Result RenderTargetVk::getImageView(vk::Context *context,
203 const vk::ImageView **imageViewOut) const
204 {
205 ASSERT(mImage);
206 return getImageViewImpl(context, *mImage, mImageViews, imageViewOut);
207 }
208
getImageViewWithColorspace(vk::Context * context,gl::SrgbWriteControlMode mode,const vk::ImageView ** imageViewOut) const209 angle::Result RenderTargetVk::getImageViewWithColorspace(vk::Context *context,
210 gl::SrgbWriteControlMode mode,
211 const vk::ImageView **imageViewOut) const
212 {
213 ASSERT(mImage);
214 mImageViews->updateSrgbWiteControlMode(*mImage, mode);
215 return getImageViewImpl(context, *mImage, mImageViews, imageViewOut);
216 }
217
getResolveImageView(vk::Context * context,const vk::ImageView ** imageViewOut) const218 angle::Result RenderTargetVk::getResolveImageView(vk::Context *context,
219 const vk::ImageView **imageViewOut) const
220 {
221 ASSERT(mResolveImage);
222 return getImageViewImpl(context, *mResolveImage, mResolveImageViews, imageViewOut);
223 }
224
getDepthOrStencilImageView(vk::Context * context,VkImageAspectFlagBits aspect,const vk::ImageView ** imageViewOut) const225 angle::Result RenderTargetVk::getDepthOrStencilImageView(vk::Context *context,
226 VkImageAspectFlagBits aspect,
227 const vk::ImageView **imageViewOut) const
228 {
229 ASSERT(mImage);
230 return getDepthOrStencilImageViewImpl(context, *mImage, mImageViews, aspect, imageViewOut);
231 }
232
getDepthOrStencilImageViewForCopy(vk::Context * context,VkImageAspectFlagBits aspect,const vk::ImageView ** imageViewOut) const233 angle::Result RenderTargetVk::getDepthOrStencilImageViewForCopy(
234 vk::Context *context,
235 VkImageAspectFlagBits aspect,
236 const vk::ImageView **imageViewOut) const
237 {
238 return isResolveImageOwnerOfData()
239 ? getResolveDepthOrStencilImageView(context, aspect, imageViewOut)
240 : getDepthOrStencilImageView(context, aspect, imageViewOut);
241 }
242
getResolveDepthOrStencilImageView(vk::Context * context,VkImageAspectFlagBits aspect,const vk::ImageView ** imageViewOut) const243 angle::Result RenderTargetVk::getResolveDepthOrStencilImageView(
244 vk::Context *context,
245 VkImageAspectFlagBits aspect,
246 const vk::ImageView **imageViewOut) const
247 {
248 ASSERT(mResolveImage);
249 return getDepthOrStencilImageViewImpl(context, *mResolveImage, mResolveImageViews, aspect,
250 imageViewOut);
251 }
252
getDepthOrStencilImageViewImpl(vk::Context * context,const vk::ImageHelper & image,vk::ImageViewHelper * imageViews,VkImageAspectFlagBits aspect,const vk::ImageView ** imageViewOut) const253 angle::Result RenderTargetVk::getDepthOrStencilImageViewImpl(
254 vk::Context *context,
255 const vk::ImageHelper &image,
256 vk::ImageViewHelper *imageViews,
257 VkImageAspectFlagBits aspect,
258 const vk::ImageView **imageViewOut) const
259 {
260 // If the image has only one aspect, the usual view is sufficient.
261 if (image.getAspectFlags() == aspect)
262 {
263 return getImageViewImpl(context, image, imageViews, imageViewOut);
264 }
265
266 // Otherwise, for images with both the depth and stencil aspects, need to create special views
267 // that select only one such aspect.
268 ASSERT(image.valid() && imageViews);
269 vk::LevelIndex levelVk = image.toVkLevel(getLevelIndexForImage(image));
270 if (mLayerCount == 1)
271 {
272 return imageViews->getLevelLayerDepthOrStencilImageView(context, image, levelVk,
273 mLayerIndex, aspect, imageViewOut);
274 }
275
276 // Layered render targets view the whole level or a handful of layers in case of multiview.
277 return imageViews->getLevelDepthOrStencilImageView(context, image, levelVk, mLayerIndex,
278 mLayerCount, aspect, imageViewOut);
279 }
280
isResolveImageOwnerOfData() const281 bool RenderTargetVk::isResolveImageOwnerOfData() const
282 {
283 // If there's a resolve attachment and the image itself is transient, it's the resolve
284 // attachment that owns the data, so all non-render-pass accesses to the render target data
285 // should go through the resolve attachment.
286 return isImageTransient();
287 }
288
getOwnerOfData() const289 vk::ImageHelper *RenderTargetVk::getOwnerOfData() const
290 {
291 return isResolveImageOwnerOfData() ? mResolveImage : mImage;
292 }
293
getCopyImageView(vk::Context * context,const vk::ImageView ** imageViewOut) const294 angle::Result RenderTargetVk::getCopyImageView(vk::Context *context,
295 const vk::ImageView **imageViewOut) const
296 {
297 const vk::ImageViewHelper *imageViews =
298 isResolveImageOwnerOfData() ? mResolveImageViews : mImageViews;
299
300 // If the source of render target is a texture or renderbuffer, this will always be valid. This
301 // is also where 3D or 2DArray images could be the source of the render target.
302 if (imageViews->hasCopyImageView())
303 {
304 *imageViewOut = &imageViews->getCopyImageView();
305 return angle::Result::Continue;
306 }
307
308 // Otherwise, this must come from the surface, in which case the image is 2D, so the image view
309 // used to draw is just as good for fetching. If resolve attachment is present, fetching is
310 // done from that.
311 return isResolveImageOwnerOfData() ? getResolveImageView(context, imageViewOut)
312 : getImageView(context, imageViewOut);
313 }
314
getImageActualFormatID() const315 angle::FormatID RenderTargetVk::getImageActualFormatID() const
316 {
317 ASSERT(mImage && mImage->valid());
318 return mImage->getActualFormatID();
319 }
320
getImageIntendedFormatID() const321 angle::FormatID RenderTargetVk::getImageIntendedFormatID() const
322 {
323 ASSERT(mImage && mImage->valid());
324 return mImage->getIntendedFormatID();
325 }
326
getImageActualFormat() const327 const angle::Format &RenderTargetVk::getImageActualFormat() const
328 {
329 ASSERT(mImage && mImage->valid());
330 return mImage->getActualFormat();
331 }
332
getImageIntendedFormat() const333 const angle::Format &RenderTargetVk::getImageIntendedFormat() const
334 {
335 ASSERT(mImage && mImage->valid());
336 return mImage->getIntendedFormat();
337 }
338
getExtents() const339 gl::Extents RenderTargetVk::getExtents() const
340 {
341 ASSERT(mImage && mImage->valid());
342 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
343 return mImage->getLevelExtents2D(levelVk);
344 }
345
getRotatedExtents() const346 gl::Extents RenderTargetVk::getRotatedExtents() const
347 {
348 ASSERT(mImage && mImage->valid());
349 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
350 return mImage->getRotatedLevelExtents2D(levelVk);
351 }
352
getLevelIndexForImage(const vk::ImageHelper & image) const353 gl::LevelIndex RenderTargetVk::getLevelIndexForImage(const vk::ImageHelper &image) const
354 {
355 return (getOwnerOfData()->getImageSerial() == image.getImageSerial()) ? mLevelIndexGL
356 : gl::LevelIndex(0);
357 }
358
updateSwapchainImage(vk::ImageHelper * image,vk::ImageViewHelper * imageViews,vk::ImageHelper * resolveImage,vk::ImageViewHelper * resolveImageViews)359 void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image,
360 vk::ImageViewHelper *imageViews,
361 vk::ImageHelper *resolveImage,
362 vk::ImageViewHelper *resolveImageViews)
363 {
364 ASSERT(image && image->valid() && imageViews);
365 mImage = image;
366 mImageViews = imageViews;
367 mResolveImage = resolveImage;
368 mResolveImageViews = resolveImageViews;
369 }
370
getImageForCopy() const371 vk::ImageHelper &RenderTargetVk::getImageForCopy() const
372 {
373 ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
374 return *getOwnerOfData();
375 }
376
getImageForWrite() const377 vk::ImageHelper &RenderTargetVk::getImageForWrite() const
378 {
379 ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
380 return *getOwnerOfData();
381 }
382
flushStagedUpdates(ContextVk * contextVk,vk::ClearValuesArray * deferredClears,uint32_t deferredClearIndex,uint32_t framebufferLayerCount)383 angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk,
384 vk::ClearValuesArray *deferredClears,
385 uint32_t deferredClearIndex,
386 uint32_t framebufferLayerCount)
387 {
388 ASSERT(mImage->valid() && (!isResolveImageOwnerOfData() || mResolveImage->valid()));
389 ASSERT(framebufferLayerCount != 0);
390
391 // It's impossible to defer clears to slices of a 3D images, as the clear applies to all the
392 // slices, while deferred clears only clear a single slice (where the framebuffer is attached).
393 // Additionally, the layer index for 3D textures is always zero according to Vulkan.
394 uint32_t layerIndex = mLayerIndex;
395 if (mImage->getType() == VK_IMAGE_TYPE_3D)
396 {
397 layerIndex = 0;
398 deferredClears = nullptr;
399 deferredClearIndex = 0;
400 }
401
402 vk::ImageHelper *image = getOwnerOfData();
403
404 // All updates should be staged on the image that owns the data as the source of truth. With
405 // multisampled-render-to-texture framebuffers, that is the resolve image. In that case, even
406 // though deferred clears set the loadOp of the transient multisampled image, the clears
407 // themselves are staged on the resolve image. The |flushSingleSubresourceStagedUpdates| call
408 // below will either flush all staged updates to the resolve image, or if the only staged update
409 // is a clear, it will accumulate it in the |deferredClears| array. Later, when the render pass
410 // is started, the deferred clears are applied to the transient multisampled image.
411 ASSERT(!isResolveImageOwnerOfData() ||
412 !mImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
413 ASSERT(isResolveImageOwnerOfData() || mResolveImage == nullptr ||
414 !mResolveImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
415
416 if (!image->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, framebufferLayerCount))
417 {
418 return angle::Result::Continue;
419 }
420
421 return image->flushSingleSubresourceStagedUpdates(contextVk, mLevelIndexGL, layerIndex,
422 framebufferLayerCount, deferredClears,
423 deferredClearIndex);
424 }
425
hasDefinedContent() const426 bool RenderTargetVk::hasDefinedContent() const
427 {
428 vk::ImageHelper *image = getOwnerOfData();
429 return image->hasSubresourceDefinedContent(mLevelIndexGL, mLayerIndex, mLayerCount);
430 }
431
hasDefinedStencilContent() const432 bool RenderTargetVk::hasDefinedStencilContent() const
433 {
434 vk::ImageHelper *image = getOwnerOfData();
435 return image->hasSubresourceDefinedStencilContent(mLevelIndexGL, mLayerIndex, mLayerCount);
436 }
437
invalidateEntireContent(ContextVk * contextVk,bool * preferToKeepContentsDefinedOut)438 void RenderTargetVk::invalidateEntireContent(ContextVk *contextVk,
439 bool *preferToKeepContentsDefinedOut)
440 {
441 vk::ImageHelper *image = getOwnerOfData();
442 image->invalidateSubresourceContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount,
443 preferToKeepContentsDefinedOut);
444 }
445
invalidateEntireStencilContent(ContextVk * contextVk,bool * preferToKeepContentsDefinedOut)446 void RenderTargetVk::invalidateEntireStencilContent(ContextVk *contextVk,
447 bool *preferToKeepContentsDefinedOut)
448 {
449 vk::ImageHelper *image = getOwnerOfData();
450 image->invalidateSubresourceStencilContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount,
451 preferToKeepContentsDefinedOut);
452 }
453
getImageIndexForClear(uint32_t layerCount) const454 gl::ImageIndex RenderTargetVk::getImageIndexForClear(uint32_t layerCount) const
455 {
456 // Determine the GL type from the Vk Image properties.
457 if (mImage->getType() == VK_IMAGE_TYPE_3D || mImage->getLayerCount() > 1)
458 {
459 // This is used for the sake of staging clears. The depth slices of the 3D image are
460 // threated as layers for this purpose.
461 //
462 // We also don't need to distinguish 2D array and cube.
463 return gl::ImageIndex::Make2DArrayRange(mLevelIndexGL.get(), mLayerIndex, layerCount);
464 }
465
466 ASSERT(mLayerIndex == 0);
467 ASSERT(mLayerCount == 1);
468 ASSERT(layerCount == 1);
469 return gl::ImageIndex::Make2D(mLevelIndexGL.get());
470 }
471 } // namespace rx
472