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
reset()67 void RenderTargetVk::reset()
68 {
69 mImage = nullptr;
70 mImageViews = nullptr;
71 mResolveImage = nullptr;
72 mResolveImageViews = nullptr;
73 mImageSiblingSerial = {};
74 mLevelIndexGL = gl::LevelIndex(0);
75 mLayerIndex = 0;
76 mLayerCount = 0;
77 }
78
getSubresourceSerialImpl(vk::ImageViewHelper * imageViews) const79 vk::ImageOrBufferViewSubresourceSerial RenderTargetVk::getSubresourceSerialImpl(
80 vk::ImageViewHelper *imageViews) const
81 {
82 ASSERT(imageViews);
83 ASSERT(mLayerIndex < std::numeric_limits<uint16_t>::max());
84 ASSERT(mLevelIndexGL.get() < std::numeric_limits<uint16_t>::max());
85
86 vk::LayerMode layerMode = vk::GetLayerMode(*mImage, mLayerCount);
87 vk::ImageOrBufferViewSubresourceSerial imageViewSerial =
88 imageViews->getSubresourceSerial(mLevelIndexGL, 1, mLayerIndex, layerMode);
89 return imageViewSerial;
90 }
91
getDrawSubresourceSerial() const92 vk::ImageOrBufferViewSubresourceSerial RenderTargetVk::getDrawSubresourceSerial() const
93 {
94 return getSubresourceSerialImpl(mImageViews);
95 }
96
getResolveSubresourceSerial() const97 vk::ImageOrBufferViewSubresourceSerial RenderTargetVk::getResolveSubresourceSerial() const
98 {
99 return getSubresourceSerialImpl(mResolveImageViews);
100 }
101
onColorDraw(ContextVk * contextVk,uint32_t framebufferLayerCount,vk::PackedAttachmentIndex packedAttachmentIndex)102 void RenderTargetVk::onColorDraw(ContextVk *contextVk,
103 uint32_t framebufferLayerCount,
104 vk::PackedAttachmentIndex packedAttachmentIndex)
105 {
106 ASSERT(!mImage->getActualFormat().hasDepthOrStencilBits());
107 ASSERT(framebufferLayerCount <= mLayerCount);
108
109 contextVk->onColorDraw(mLevelIndexGL, mLayerIndex, framebufferLayerCount, mImage, mResolveImage,
110 mImageSiblingSerial, packedAttachmentIndex);
111
112 // Multisampled render to texture framebuffers cannot be layered.
113 ASSERT(mResolveImage == nullptr || framebufferLayerCount == 1);
114 }
115
onColorResolve(ContextVk * contextVk,uint32_t framebufferLayerCount,size_t readColorIndexGL,const vk::ImageView & view)116 void RenderTargetVk::onColorResolve(ContextVk *contextVk,
117 uint32_t framebufferLayerCount,
118 size_t readColorIndexGL,
119 const vk::ImageView &view)
120 {
121 ASSERT(!mImage->getActualFormat().hasDepthOrStencilBits());
122 ASSERT(framebufferLayerCount <= mLayerCount);
123 ASSERT(mResolveImage == nullptr);
124
125 // The currently open render pass is from the read framebuffer. This is the draw framebuffer's
126 // render target. Ask the context to add this image as the resolve attachment to the read
127 // framebuffer's render pass, at the given color index.
128 contextVk->onColorResolve(mLevelIndexGL, mLayerIndex, framebufferLayerCount, mImage,
129 view.getHandle(), mImageSiblingSerial, readColorIndexGL);
130 }
131
onDepthStencilDraw(ContextVk * contextVk,uint32_t framebufferLayerCount)132 void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk, uint32_t framebufferLayerCount)
133 {
134 const angle::Format &format = mImage->getActualFormat();
135 ASSERT(format.hasDepthOrStencilBits());
136 ASSERT(framebufferLayerCount <= mLayerCount);
137
138 contextVk->onDepthStencilDraw(mLevelIndexGL, mLayerIndex, framebufferLayerCount, mImage,
139 mResolveImage, mImageSiblingSerial);
140 }
141
onDepthStencilResolve(ContextVk * contextVk,uint32_t framebufferLayerCount,VkImageAspectFlags aspects,const vk::ImageView & view)142 void RenderTargetVk::onDepthStencilResolve(ContextVk *contextVk,
143 uint32_t framebufferLayerCount,
144 VkImageAspectFlags aspects,
145 const vk::ImageView &view)
146 {
147 ASSERT(mImage->getActualFormat().hasDepthOrStencilBits());
148 ASSERT(framebufferLayerCount <= mLayerCount);
149 ASSERT(mResolveImage == nullptr);
150
151 contextVk->onDepthStencilResolve(mLevelIndexGL, mLayerIndex, framebufferLayerCount, aspects,
152 mImage, view.getHandle(), mImageSiblingSerial);
153 }
154
getImageForRenderPass()155 vk::ImageHelper &RenderTargetVk::getImageForRenderPass()
156 {
157 ASSERT(mImage && mImage->valid());
158 return *mImage;
159 }
160
getImageForRenderPass() const161 const vk::ImageHelper &RenderTargetVk::getImageForRenderPass() const
162 {
163 ASSERT(mImage && mImage->valid());
164 return *mImage;
165 }
166
getResolveImageForRenderPass()167 vk::ImageHelper &RenderTargetVk::getResolveImageForRenderPass()
168 {
169 ASSERT(mResolveImage && mResolveImage->valid());
170 return *mResolveImage;
171 }
172
getResolveImageForRenderPass() const173 const vk::ImageHelper &RenderTargetVk::getResolveImageForRenderPass() const
174 {
175 ASSERT(mResolveImage && mResolveImage->valid());
176 return *mResolveImage;
177 }
178
getImageViewImpl(vk::ErrorContext * context,const vk::ImageHelper & image,vk::ImageViewHelper * imageViews,const vk::ImageView ** imageViewOut) const179 angle::Result RenderTargetVk::getImageViewImpl(vk::ErrorContext *context,
180 const vk::ImageHelper &image,
181 vk::ImageViewHelper *imageViews,
182 const vk::ImageView **imageViewOut) const
183 {
184 ASSERT(image.valid() && imageViews);
185 vk::LevelIndex levelVk = image.toVkLevel(getLevelIndexForImage(image));
186 if (mLayerCount == 1)
187 {
188 return imageViews->getLevelLayerDrawImageView(context, image, levelVk, mLayerIndex,
189 imageViewOut);
190 }
191
192 // Layered render targets view the whole level or a handful of layers in case of multiview.
193 return imageViews->getLevelDrawImageView(context, image, levelVk, mLayerIndex, mLayerCount,
194 imageViewOut);
195 }
196
getImageView(vk::ErrorContext * context,const vk::ImageView ** imageViewOut) const197 angle::Result RenderTargetVk::getImageView(vk::ErrorContext *context,
198 const vk::ImageView **imageViewOut) const
199 {
200 ASSERT(mImage);
201 return getImageViewImpl(context, *mImage, mImageViews, imageViewOut);
202 }
203
getImageViewWithColorspace(vk::ErrorContext * context,gl::SrgbWriteControlMode mode,const vk::ImageView ** imageViewOut) const204 angle::Result RenderTargetVk::getImageViewWithColorspace(vk::ErrorContext *context,
205 gl::SrgbWriteControlMode mode,
206 const vk::ImageView **imageViewOut) const
207 {
208 ASSERT(mImage);
209 mImageViews->updateSrgbWiteControlMode(*mImage, mode);
210 return getImageViewImpl(context, *mImage, mImageViews, imageViewOut);
211 }
212
getResolveImageView(vk::ErrorContext * context,const vk::ImageView ** imageViewOut) const213 angle::Result RenderTargetVk::getResolveImageView(vk::ErrorContext *context,
214 const vk::ImageView **imageViewOut) const
215 {
216 ASSERT(mResolveImage);
217 return getImageViewImpl(context, *mResolveImage, mResolveImageViews, imageViewOut);
218 }
219
getDepthOrStencilImageView(vk::ErrorContext * context,VkImageAspectFlagBits aspect,const vk::ImageView ** imageViewOut) const220 angle::Result RenderTargetVk::getDepthOrStencilImageView(vk::ErrorContext *context,
221 VkImageAspectFlagBits aspect,
222 const vk::ImageView **imageViewOut) const
223 {
224 ASSERT(mImage);
225 return getDepthOrStencilImageViewImpl(context, *mImage, mImageViews, aspect, imageViewOut);
226 }
227
getDepthOrStencilImageViewForCopy(vk::ErrorContext * context,VkImageAspectFlagBits aspect,const vk::ImageView ** imageViewOut) const228 angle::Result RenderTargetVk::getDepthOrStencilImageViewForCopy(
229 vk::ErrorContext *context,
230 VkImageAspectFlagBits aspect,
231 const vk::ImageView **imageViewOut) const
232 {
233 return isResolveImageOwnerOfData()
234 ? getResolveDepthOrStencilImageView(context, aspect, imageViewOut)
235 : getDepthOrStencilImageView(context, aspect, imageViewOut);
236 }
237
getResolveDepthOrStencilImageView(vk::ErrorContext * context,VkImageAspectFlagBits aspect,const vk::ImageView ** imageViewOut) const238 angle::Result RenderTargetVk::getResolveDepthOrStencilImageView(
239 vk::ErrorContext *context,
240 VkImageAspectFlagBits aspect,
241 const vk::ImageView **imageViewOut) const
242 {
243 ASSERT(mResolveImage);
244 return getDepthOrStencilImageViewImpl(context, *mResolveImage, mResolveImageViews, aspect,
245 imageViewOut);
246 }
247
getDepthOrStencilImageViewImpl(vk::ErrorContext * context,const vk::ImageHelper & image,vk::ImageViewHelper * imageViews,VkImageAspectFlagBits aspect,const vk::ImageView ** imageViewOut) const248 angle::Result RenderTargetVk::getDepthOrStencilImageViewImpl(
249 vk::ErrorContext *context,
250 const vk::ImageHelper &image,
251 vk::ImageViewHelper *imageViews,
252 VkImageAspectFlagBits aspect,
253 const vk::ImageView **imageViewOut) const
254 {
255 // If the image has only one aspect, the usual view is sufficient.
256 if (image.getAspectFlags() == aspect)
257 {
258 return getImageViewImpl(context, image, imageViews, imageViewOut);
259 }
260
261 // Otherwise, for images with both the depth and stencil aspects, need to create special views
262 // that select only one such aspect.
263 ASSERT(image.valid() && imageViews);
264 vk::LevelIndex levelVk = image.toVkLevel(getLevelIndexForImage(image));
265 if (mLayerCount == 1)
266 {
267 return imageViews->getLevelLayerDepthOrStencilImageView(context, image, levelVk,
268 mLayerIndex, aspect, imageViewOut);
269 }
270
271 // Layered render targets view the whole level or a handful of layers in case of multiview.
272 return imageViews->getLevelDepthOrStencilImageView(context, image, levelVk, mLayerIndex,
273 mLayerCount, aspect, imageViewOut);
274 }
275
isResolveImageOwnerOfData() const276 bool RenderTargetVk::isResolveImageOwnerOfData() const
277 {
278 // If there's a resolve attachment and the image itself is transient, it's the resolve
279 // attachment that owns the data, so all non-render-pass accesses to the render target data
280 // should go through the resolve attachment.
281 return isImageTransient();
282 }
283
getOwnerOfData() const284 vk::ImageHelper *RenderTargetVk::getOwnerOfData() const
285 {
286 return isResolveImageOwnerOfData() ? mResolveImage : mImage;
287 }
288
getCopyImageView(vk::ErrorContext * context,const vk::ImageView ** imageViewOut) const289 angle::Result RenderTargetVk::getCopyImageView(vk::ErrorContext *context,
290 const vk::ImageView **imageViewOut) const
291 {
292 const vk::ImageViewHelper *imageViews =
293 isResolveImageOwnerOfData() ? mResolveImageViews : mImageViews;
294
295 // If the source of render target is a texture or renderbuffer, this will always be valid. This
296 // is also where 3D or 2DArray images could be the source of the render target.
297 if (imageViews->hasCopyImageView())
298 {
299 *imageViewOut = &imageViews->getCopyImageView();
300 return angle::Result::Continue;
301 }
302
303 // Otherwise, this must come from the surface, in which case the image is 2D, so the image view
304 // used to draw is just as good for fetching. If resolve attachment is present, fetching is
305 // done from that.
306 return isResolveImageOwnerOfData() ? getResolveImageView(context, imageViewOut)
307 : getImageView(context, imageViewOut);
308 }
309
getImageActualFormatID() const310 angle::FormatID RenderTargetVk::getImageActualFormatID() const
311 {
312 ASSERT(mImage && mImage->valid());
313 return mImage->getActualFormatID();
314 }
315
getImageIntendedFormatID() const316 angle::FormatID RenderTargetVk::getImageIntendedFormatID() const
317 {
318 ASSERT(mImage && mImage->valid());
319 return mImage->getIntendedFormatID();
320 }
321
getImageActualFormat() const322 const angle::Format &RenderTargetVk::getImageActualFormat() const
323 {
324 ASSERT(mImage && mImage->valid());
325 return mImage->getActualFormat();
326 }
327
getImageIntendedFormat() const328 const angle::Format &RenderTargetVk::getImageIntendedFormat() const
329 {
330 ASSERT(mImage && mImage->valid());
331 return mImage->getIntendedFormat();
332 }
333
getExtents() const334 gl::Extents RenderTargetVk::getExtents() const
335 {
336 ASSERT(mImage && mImage->valid());
337 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
338 return mImage->getLevelExtents2D(levelVk);
339 }
340
getRotatedExtents() const341 gl::Extents RenderTargetVk::getRotatedExtents() const
342 {
343 ASSERT(mImage && mImage->valid());
344 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
345 return mImage->getRotatedLevelExtents2D(levelVk);
346 }
347
getLevelIndexForImage(const vk::ImageHelper & image) const348 gl::LevelIndex RenderTargetVk::getLevelIndexForImage(const vk::ImageHelper &image) const
349 {
350 return (getOwnerOfData()->getImageSerial() == image.getImageSerial()) ? mLevelIndexGL
351 : gl::LevelIndex(0);
352 }
353
updateSwapchainImage(vk::ImageHelper * image,vk::ImageViewHelper * imageViews,vk::ImageHelper * resolveImage,vk::ImageViewHelper * resolveImageViews)354 void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image,
355 vk::ImageViewHelper *imageViews,
356 vk::ImageHelper *resolveImage,
357 vk::ImageViewHelper *resolveImageViews)
358 {
359 ASSERT(image && image->valid() && imageViews);
360 ASSERT(!mImageSiblingSerial.valid());
361 ASSERT(mLevelIndexGL == gl::LevelIndex(0));
362 ASSERT(mLayerIndex == 0);
363 mImage = image;
364 mImageViews = imageViews;
365 mResolveImage = resolveImage;
366 mResolveImageViews = resolveImageViews;
367 mLayerCount = 1;
368 }
369
getImageForCopy() const370 vk::ImageHelper &RenderTargetVk::getImageForCopy() const
371 {
372 ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
373 return *getOwnerOfData();
374 }
375
getImageForWrite() const376 vk::ImageHelper &RenderTargetVk::getImageForWrite() const
377 {
378 ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
379 return *getOwnerOfData();
380 }
381
flushStagedUpdates(ContextVk * contextVk,vk::ClearValuesArray * deferredClears,uint32_t deferredClearIndex,uint32_t framebufferLayerCount)382 angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk,
383 vk::ClearValuesArray *deferredClears,
384 uint32_t deferredClearIndex,
385 uint32_t framebufferLayerCount)
386 {
387 ASSERT(mImage->valid() && (!isResolveImageOwnerOfData() || mResolveImage->valid()));
388 ASSERT(framebufferLayerCount != 0);
389
390 // It's impossible to defer clears to slices of a 3D images, as the clear applies to all the
391 // slices, while deferred clears only clear a single slice (where the framebuffer is attached).
392 // Additionally, the layer index for 3D textures is always zero according to Vulkan.
393 uint32_t layerIndex = mLayerIndex;
394 if (mImage->getType() == VK_IMAGE_TYPE_3D)
395 {
396 layerIndex = 0;
397 deferredClears = nullptr;
398 deferredClearIndex = 0;
399 }
400
401 vk::ImageHelper *image = getOwnerOfData();
402
403 // All updates should be staged on the image that owns the data as the source of truth. With
404 // multisampled-render-to-texture framebuffers, that is the resolve image. In that case, even
405 // though deferred clears set the loadOp of the transient multisampled image, the clears
406 // themselves are staged on the resolve image. The |flushSingleSubresourceStagedUpdates| call
407 // below will either flush all staged updates to the resolve image, or if the only staged update
408 // is a clear, it will accumulate it in the |deferredClears| array. Later, when the render pass
409 // is started, the deferred clears are applied to the transient multisampled image.
410 ASSERT(!isResolveImageOwnerOfData() ||
411 !mImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
412 ASSERT(isResolveImageOwnerOfData() || mResolveImage == nullptr ||
413 !mResolveImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
414
415 if (!image->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, framebufferLayerCount))
416 {
417 return angle::Result::Continue;
418 }
419
420 return image->flushSingleSubresourceStagedUpdates(contextVk, mLevelIndexGL, layerIndex,
421 framebufferLayerCount, deferredClears,
422 deferredClearIndex);
423 }
424
hasDefinedContent() const425 bool RenderTargetVk::hasDefinedContent() const
426 {
427 vk::ImageHelper *image = getOwnerOfData();
428 return image->hasSubresourceDefinedContent(mLevelIndexGL, mLayerIndex, mLayerCount);
429 }
430
hasDefinedStencilContent() const431 bool RenderTargetVk::hasDefinedStencilContent() const
432 {
433 vk::ImageHelper *image = getOwnerOfData();
434 return image->hasSubresourceDefinedStencilContent(mLevelIndexGL, mLayerIndex, mLayerCount);
435 }
436
invalidateEntireContent(ContextVk * contextVk,bool * preferToKeepContentsDefinedOut)437 void RenderTargetVk::invalidateEntireContent(ContextVk *contextVk,
438 bool *preferToKeepContentsDefinedOut)
439 {
440 vk::ImageHelper *image = getOwnerOfData();
441 image->invalidateSubresourceContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount,
442 preferToKeepContentsDefinedOut);
443 }
444
invalidateEntireStencilContent(ContextVk * contextVk,bool * preferToKeepContentsDefinedOut)445 void RenderTargetVk::invalidateEntireStencilContent(ContextVk *contextVk,
446 bool *preferToKeepContentsDefinedOut)
447 {
448 vk::ImageHelper *image = getOwnerOfData();
449 image->invalidateSubresourceStencilContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount,
450 preferToKeepContentsDefinedOut);
451 }
452
getImageIndexForClear(uint32_t layerCount) const453 gl::ImageIndex RenderTargetVk::getImageIndexForClear(uint32_t layerCount) const
454 {
455 // Determine the GL type from the Vk Image properties.
456 if (mImage->getType() == VK_IMAGE_TYPE_3D || mImage->getLayerCount() > 1)
457 {
458 // This is used for the sake of staging clears. The depth slices of the 3D image are
459 // threated as layers for this purpose.
460 //
461 // We also don't need to distinguish 2D array and cube.
462 return gl::ImageIndex::Make2DArrayRange(mLevelIndexGL.get(), mLayerIndex, layerCount);
463 }
464
465 ASSERT(mLayerIndex == 0);
466 ASSERT(mLayerCount == 1);
467 ASSERT(layerCount == 1);
468 return gl::ImageIndex::Make2D(mLevelIndexGL.get());
469 }
470 } // namespace rx
471