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 vk::SrgbDecodeMode::SkipDecode, gl::SrgbOverride::Default);
90 return imageViewSerial;
91 }
92
getDrawSubresourceSerial() const93 vk::ImageOrBufferViewSubresourceSerial RenderTargetVk::getDrawSubresourceSerial() const
94 {
95 return getSubresourceSerialImpl(mImageViews);
96 }
97
getResolveSubresourceSerial() const98 vk::ImageOrBufferViewSubresourceSerial RenderTargetVk::getResolveSubresourceSerial() const
99 {
100 return getSubresourceSerialImpl(mResolveImageViews);
101 }
102
onColorDraw(ContextVk * contextVk,uint32_t framebufferLayerCount,vk::PackedAttachmentIndex packedAttachmentIndex)103 void RenderTargetVk::onColorDraw(ContextVk *contextVk,
104 uint32_t framebufferLayerCount,
105 vk::PackedAttachmentIndex packedAttachmentIndex)
106 {
107 ASSERT(!mImage->getActualFormat().hasDepthOrStencilBits());
108 ASSERT(framebufferLayerCount <= mLayerCount);
109
110 contextVk->onColorDraw(mLevelIndexGL, mLayerIndex, framebufferLayerCount, mImage, mResolveImage,
111 mImageSiblingSerial, packedAttachmentIndex);
112
113 // Multisampled render to texture framebuffers cannot be layered.
114 ASSERT(mResolveImage == nullptr || framebufferLayerCount == 1);
115 }
116
onColorResolve(ContextVk * contextVk,uint32_t framebufferLayerCount)117 void RenderTargetVk::onColorResolve(ContextVk *contextVk, uint32_t framebufferLayerCount)
118 {
119 ASSERT(!mImage->getActualFormat().hasDepthOrStencilBits());
120 ASSERT(framebufferLayerCount <= mLayerCount);
121 ASSERT(mResolveImage == nullptr);
122
123 contextVk->onImageRenderPassWrite(mLevelIndexGL, mLayerIndex, framebufferLayerCount,
124 VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorWrite,
125 mImage);
126 }
127
onDepthStencilDraw(ContextVk * contextVk,uint32_t framebufferLayerCount)128 void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk, uint32_t framebufferLayerCount)
129 {
130 const angle::Format &format = mImage->getActualFormat();
131 ASSERT(format.hasDepthOrStencilBits());
132 ASSERT(framebufferLayerCount <= mLayerCount);
133
134 contextVk->onDepthStencilDraw(mLevelIndexGL, mLayerIndex, framebufferLayerCount, mImage,
135 mResolveImage, mImageSiblingSerial);
136 }
137
onDepthStencilResolve(ContextVk * contextVk,uint32_t framebufferLayerCount)138 void RenderTargetVk::onDepthStencilResolve(ContextVk *contextVk, uint32_t framebufferLayerCount)
139 {
140 ASSERT(mImage->getActualFormat().hasDepthOrStencilBits());
141 ASSERT(framebufferLayerCount <= mLayerCount);
142 ASSERT(mResolveImage == nullptr);
143
144 contextVk->onImageRenderPassWrite(mLevelIndexGL, mLayerIndex, framebufferLayerCount,
145 mImage->getAspectFlags(),
146 vk::ImageLayout::DepthStencilResolve, mImage);
147 }
148
getImageForRenderPass()149 vk::ImageHelper &RenderTargetVk::getImageForRenderPass()
150 {
151 ASSERT(mImage && mImage->valid());
152 return *mImage;
153 }
154
getImageForRenderPass() const155 const vk::ImageHelper &RenderTargetVk::getImageForRenderPass() const
156 {
157 ASSERT(mImage && mImage->valid());
158 return *mImage;
159 }
160
getResolveImageForRenderPass()161 vk::ImageHelper &RenderTargetVk::getResolveImageForRenderPass()
162 {
163 ASSERT(mResolveImage && mResolveImage->valid());
164 return *mResolveImage;
165 }
166
getResolveImageForRenderPass() const167 const vk::ImageHelper &RenderTargetVk::getResolveImageForRenderPass() const
168 {
169 ASSERT(mResolveImage && mResolveImage->valid());
170 return *mResolveImage;
171 }
172
getImageViewImpl(vk::Context * context,const vk::ImageHelper & image,gl::SrgbWriteControlMode mode,vk::ImageViewHelper * imageViews,const vk::ImageView ** imageViewOut) const173 angle::Result RenderTargetVk::getImageViewImpl(vk::Context *context,
174 const vk::ImageHelper &image,
175 gl::SrgbWriteControlMode mode,
176 vk::ImageViewHelper *imageViews,
177 const vk::ImageView **imageViewOut) const
178 {
179 ASSERT(image.valid() && imageViews);
180 vk::LevelIndex levelVk = image.toVkLevel(getLevelIndexForImage(image));
181 if (mLayerCount == 1)
182 {
183 return imageViews->getLevelLayerDrawImageView(context, image, levelVk, mLayerIndex, mode,
184 imageViewOut);
185 }
186
187 // Layered render targets view the whole level or a handful of layers in case of multiview.
188 return imageViews->getLevelDrawImageView(context, image, levelVk, mLayerIndex, mLayerCount,
189 mode, imageViewOut);
190 }
191
getImageView(vk::Context * context,const vk::ImageView ** imageViewOut) const192 angle::Result RenderTargetVk::getImageView(vk::Context *context,
193 const vk::ImageView **imageViewOut) const
194 {
195 ASSERT(mImage);
196 return getImageViewImpl(context, *mImage, gl::SrgbWriteControlMode::Default, mImageViews,
197 imageViewOut);
198 }
199
getImageViewWithColorspace(vk::Context * context,gl::SrgbWriteControlMode mode,const vk::ImageView ** imageViewOut) const200 angle::Result RenderTargetVk::getImageViewWithColorspace(vk::Context *context,
201 gl::SrgbWriteControlMode mode,
202 const vk::ImageView **imageViewOut) const
203 {
204 ASSERT(mImage);
205 return getImageViewImpl(context, *mImage, mode, mImageViews, imageViewOut);
206 }
207
getResolveImageView(vk::Context * context,const vk::ImageView ** imageViewOut) const208 angle::Result RenderTargetVk::getResolveImageView(vk::Context *context,
209 const vk::ImageView **imageViewOut) const
210 {
211 ASSERT(mResolveImage);
212 return getImageViewImpl(context, *mResolveImage, gl::SrgbWriteControlMode::Default,
213 mResolveImageViews, imageViewOut);
214 }
215
isResolveImageOwnerOfData() const216 bool RenderTargetVk::isResolveImageOwnerOfData() const
217 {
218 // If there's a resolve attachment and the image itself is transient, it's the resolve
219 // attachment that owns the data, so all non-render-pass accesses to the render target data
220 // should go through the resolve attachment.
221 return isImageTransient();
222 }
223
getOwnerOfData() const224 vk::ImageHelper *RenderTargetVk::getOwnerOfData() const
225 {
226 return isResolveImageOwnerOfData() ? mResolveImage : mImage;
227 }
228
getCopyImageView(vk::Context * context,const vk::ImageView ** imageViewOut) const229 angle::Result RenderTargetVk::getCopyImageView(vk::Context *context,
230 const vk::ImageView **imageViewOut) const
231 {
232 const vk::ImageViewHelper *imageViews =
233 isResolveImageOwnerOfData() ? mResolveImageViews : mImageViews;
234
235 // If the source of render target is a texture or renderbuffer, this will always be valid. This
236 // is also where 3D or 2DArray images could be the source of the render target.
237 if (imageViews->hasCopyImageView())
238 {
239 *imageViewOut = &imageViews->getCopyImageView();
240 return angle::Result::Continue;
241 }
242
243 // Otherwise, this must come from the surface, in which case the image is 2D, so the image view
244 // used to draw is just as good for fetching. If resolve attachment is present, fetching is
245 // done from that.
246 return isResolveImageOwnerOfData() ? getResolveImageView(context, imageViewOut)
247 : getImageView(context, imageViewOut);
248 }
249
getImageActualFormatID() const250 angle::FormatID RenderTargetVk::getImageActualFormatID() const
251 {
252 ASSERT(mImage && mImage->valid());
253 return mImage->getActualFormatID();
254 }
255
getImageIntendedFormatID() const256 angle::FormatID RenderTargetVk::getImageIntendedFormatID() const
257 {
258 ASSERT(mImage && mImage->valid());
259 return mImage->getIntendedFormatID();
260 }
261
getImageActualFormat() const262 const angle::Format &RenderTargetVk::getImageActualFormat() const
263 {
264 ASSERT(mImage && mImage->valid());
265 return mImage->getActualFormat();
266 }
267
getImageIntendedFormat() const268 const angle::Format &RenderTargetVk::getImageIntendedFormat() const
269 {
270 ASSERT(mImage && mImage->valid());
271 return mImage->getIntendedFormat();
272 }
273
getExtents() const274 gl::Extents RenderTargetVk::getExtents() const
275 {
276 ASSERT(mImage && mImage->valid());
277 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
278 return mImage->getLevelExtents2D(levelVk);
279 }
280
getRotatedExtents() const281 gl::Extents RenderTargetVk::getRotatedExtents() const
282 {
283 ASSERT(mImage && mImage->valid());
284 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
285 return mImage->getRotatedLevelExtents2D(levelVk);
286 }
287
getLevelIndexForImage(const vk::ImageHelper & image) const288 gl::LevelIndex RenderTargetVk::getLevelIndexForImage(const vk::ImageHelper &image) const
289 {
290 return (getOwnerOfData()->getImageSerial() == image.getImageSerial()) ? mLevelIndexGL
291 : gl::LevelIndex(0);
292 }
293
updateSwapchainImage(vk::ImageHelper * image,vk::ImageViewHelper * imageViews,vk::ImageHelper * resolveImage,vk::ImageViewHelper * resolveImageViews)294 void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image,
295 vk::ImageViewHelper *imageViews,
296 vk::ImageHelper *resolveImage,
297 vk::ImageViewHelper *resolveImageViews)
298 {
299 ASSERT(image && image->valid() && imageViews);
300 mImage = image;
301 mImageViews = imageViews;
302 mResolveImage = resolveImage;
303 mResolveImageViews = resolveImageViews;
304 }
305
getImageForCopy() const306 vk::ImageHelper &RenderTargetVk::getImageForCopy() const
307 {
308 ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
309 return *getOwnerOfData();
310 }
311
getImageForWrite() const312 vk::ImageHelper &RenderTargetVk::getImageForWrite() const
313 {
314 ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
315 return *getOwnerOfData();
316 }
317
flushStagedUpdates(ContextVk * contextVk,vk::ClearValuesArray * deferredClears,uint32_t deferredClearIndex,uint32_t framebufferLayerCount)318 angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk,
319 vk::ClearValuesArray *deferredClears,
320 uint32_t deferredClearIndex,
321 uint32_t framebufferLayerCount)
322 {
323 ASSERT(mImage->valid() && (!isResolveImageOwnerOfData() || mResolveImage->valid()));
324 ASSERT(framebufferLayerCount != 0);
325
326 // It's impossible to defer clears to slices of a 3D images, as the clear applies to all the
327 // slices, while deferred clears only clear a single slice (where the framebuffer is attached).
328 // Additionally, the layer index for 3D textures is always zero according to Vulkan.
329 uint32_t layerIndex = mLayerIndex;
330 if (mImage->getType() == VK_IMAGE_TYPE_3D)
331 {
332 layerIndex = 0;
333 deferredClears = nullptr;
334 deferredClearIndex = 0;
335 }
336
337 vk::ImageHelper *image = getOwnerOfData();
338
339 // All updates should be staged on the image that owns the data as the source of truth. With
340 // multisampled-render-to-texture framebuffers, that is the resolve image. In that case, even
341 // though deferred clears set the loadOp of the transient multisampled image, the clears
342 // themselves are staged on the resolve image. The |flushSingleSubresourceStagedUpdates| call
343 // below will either flush all staged updates to the resolve image, or if the only staged update
344 // is a clear, it will accumulate it in the |deferredClears| array. Later, when the render pass
345 // is started, the deferred clears are applied to the transient multisampled image.
346 ASSERT(!isResolveImageOwnerOfData() ||
347 !mImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
348 ASSERT(isResolveImageOwnerOfData() || mResolveImage == nullptr ||
349 !mResolveImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
350
351 if (!image->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, framebufferLayerCount))
352 {
353 return angle::Result::Continue;
354 }
355
356 return image->flushSingleSubresourceStagedUpdates(contextVk, mLevelIndexGL, layerIndex,
357 framebufferLayerCount, deferredClears,
358 deferredClearIndex);
359 }
360
hasDefinedContent() const361 bool RenderTargetVk::hasDefinedContent() const
362 {
363 vk::ImageHelper *image = getOwnerOfData();
364 return image->hasSubresourceDefinedContent(mLevelIndexGL, mLayerIndex, mLayerCount);
365 }
366
hasDefinedStencilContent() const367 bool RenderTargetVk::hasDefinedStencilContent() const
368 {
369 vk::ImageHelper *image = getOwnerOfData();
370 return image->hasSubresourceDefinedStencilContent(mLevelIndexGL, mLayerIndex, mLayerCount);
371 }
372
invalidateEntireContent(ContextVk * contextVk,bool * preferToKeepContentsDefinedOut)373 void RenderTargetVk::invalidateEntireContent(ContextVk *contextVk,
374 bool *preferToKeepContentsDefinedOut)
375 {
376 vk::ImageHelper *image = getOwnerOfData();
377 image->invalidateSubresourceContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount,
378 preferToKeepContentsDefinedOut);
379 }
380
invalidateEntireStencilContent(ContextVk * contextVk,bool * preferToKeepContentsDefinedOut)381 void RenderTargetVk::invalidateEntireStencilContent(ContextVk *contextVk,
382 bool *preferToKeepContentsDefinedOut)
383 {
384 vk::ImageHelper *image = getOwnerOfData();
385 image->invalidateSubresourceStencilContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount,
386 preferToKeepContentsDefinedOut);
387 }
388
getImageIndexForClear(uint32_t layerCount) const389 gl::ImageIndex RenderTargetVk::getImageIndexForClear(uint32_t layerCount) const
390 {
391 // Determine the GL type from the Vk Image properties.
392 if (mImage->getType() == VK_IMAGE_TYPE_3D || mImage->getLayerCount() > 1)
393 {
394 // This is used for the sake of staging clears. The depth slices of the 3D image are
395 // threated as layers for this purpose.
396 //
397 // We also don't need to distinguish 2D array and cube.
398 return gl::ImageIndex::Make2DArrayRange(mLevelIndexGL.get(), mLayerIndex, layerCount);
399 }
400
401 ASSERT(mLayerIndex == 0);
402 ASSERT(mLayerCount == 1);
403 ASSERT(layerCount == 1);
404 return gl::ImageIndex::Make2D(mLevelIndexGL.get());
405 }
406 } // namespace rx
407