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 {
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::ImageOrBufferViewSubresourceSerial imageViewSerial = imageViews->getSubresourceSerial(
87 mLevelIndexGL, 1, mLayerIndex, vk::GetLayerMode(*mImage, mLayerCount),
88 vk::SrgbDecodeMode::SkipDecode, gl::SrgbOverride::Default);
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)116 void RenderTargetVk::onColorResolve(ContextVk *contextVk, uint32_t framebufferLayerCount)
117 {
118 ASSERT(!mImage->getActualFormat().hasDepthOrStencilBits());
119 ASSERT(framebufferLayerCount <= mLayerCount);
120 ASSERT(mResolveImage == nullptr);
121
122 contextVk->onImageRenderPassWrite(mLevelIndexGL, mLayerIndex, framebufferLayerCount,
123 VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorWrite,
124 mImage);
125 }
126
onDepthStencilDraw(ContextVk * contextVk,uint32_t framebufferLayerCount)127 void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk, uint32_t framebufferLayerCount)
128 {
129 const angle::Format &format = mImage->getActualFormat();
130 ASSERT(format.hasDepthOrStencilBits());
131 ASSERT(framebufferLayerCount <= mLayerCount);
132
133 contextVk->onDepthStencilDraw(mLevelIndexGL, mLayerIndex, framebufferLayerCount, mImage,
134 mResolveImage, mImageSiblingSerial);
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(vk::Context * context,const vk::ImageHelper & image,gl::SrgbWriteControlMode mode,vk::ImageViewHelper * imageViews,const vk::ImageView ** imageViewOut) const161 angle::Result RenderTargetVk::getImageViewImpl(vk::Context *context,
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(context, 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(context, image, levelVk, mLayerIndex, mLayerCount,
177 mode, imageViewOut);
178 }
179
getImageView(vk::Context * context,const vk::ImageView ** imageViewOut) const180 angle::Result RenderTargetVk::getImageView(vk::Context *context,
181 const vk::ImageView **imageViewOut) const
182 {
183 ASSERT(mImage);
184 return getImageViewImpl(context, *mImage, gl::SrgbWriteControlMode::Default, mImageViews,
185 imageViewOut);
186 }
187
getImageViewWithColorspace(vk::Context * context,gl::SrgbWriteControlMode mode,const vk::ImageView ** imageViewOut) const188 angle::Result RenderTargetVk::getImageViewWithColorspace(vk::Context *context,
189 gl::SrgbWriteControlMode mode,
190 const vk::ImageView **imageViewOut) const
191 {
192 ASSERT(mImage);
193 return getImageViewImpl(context, *mImage, mode, mImageViews, imageViewOut);
194 }
195
getResolveImageView(vk::Context * context,const vk::ImageView ** imageViewOut) const196 angle::Result RenderTargetVk::getResolveImageView(vk::Context *context,
197 const vk::ImageView **imageViewOut) const
198 {
199 ASSERT(mResolveImage);
200 return getImageViewImpl(context, *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
getCopyImageView(vk::Context * context,const vk::ImageView ** imageViewOut) const217 angle::Result RenderTargetVk::getCopyImageView(vk::Context *context,
218 const vk::ImageView **imageViewOut) const
219 {
220 const vk::ImageViewHelper *imageViews =
221 isResolveImageOwnerOfData() ? mResolveImageViews : mImageViews;
222
223 // If the source of render target is a texture or renderbuffer, this will always be valid. This
224 // is also where 3D or 2DArray images could be the source of the render target.
225 if (imageViews->hasCopyImageView())
226 {
227 *imageViewOut = &imageViews->getCopyImageView();
228 return angle::Result::Continue;
229 }
230
231 // Otherwise, this must come from the surface, in which case the image is 2D, so the image view
232 // used to draw is just as good for fetching. If resolve attachment is present, fetching is
233 // done from that.
234 return isResolveImageOwnerOfData() ? getResolveImageView(context, imageViewOut)
235 : getImageView(context, imageViewOut);
236 }
237
getImageActualFormatID() const238 angle::FormatID RenderTargetVk::getImageActualFormatID() const
239 {
240 ASSERT(mImage && mImage->valid());
241 return mImage->getActualFormatID();
242 }
243
getImageIntendedFormatID() const244 angle::FormatID RenderTargetVk::getImageIntendedFormatID() const
245 {
246 ASSERT(mImage && mImage->valid());
247 return mImage->getIntendedFormatID();
248 }
249
getImageActualFormat() const250 const angle::Format &RenderTargetVk::getImageActualFormat() const
251 {
252 ASSERT(mImage && mImage->valid());
253 return mImage->getActualFormat();
254 }
255
getImageIntendedFormat() const256 const angle::Format &RenderTargetVk::getImageIntendedFormat() const
257 {
258 ASSERT(mImage && mImage->valid());
259 return mImage->getIntendedFormat();
260 }
261
getExtents() const262 gl::Extents RenderTargetVk::getExtents() const
263 {
264 ASSERT(mImage && mImage->valid());
265 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
266 return mImage->getLevelExtents2D(levelVk);
267 }
268
getRotatedExtents() const269 gl::Extents RenderTargetVk::getRotatedExtents() const
270 {
271 ASSERT(mImage && mImage->valid());
272 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
273 return mImage->getRotatedLevelExtents2D(levelVk);
274 }
275
updateSwapchainImage(vk::ImageHelper * image,vk::ImageViewHelper * imageViews,vk::ImageHelper * resolveImage,vk::ImageViewHelper * resolveImageViews)276 void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image,
277 vk::ImageViewHelper *imageViews,
278 vk::ImageHelper *resolveImage,
279 vk::ImageViewHelper *resolveImageViews)
280 {
281 ASSERT(image && image->valid() && imageViews);
282 mImage = image;
283 mImageViews = imageViews;
284 mResolveImage = resolveImage;
285 mResolveImageViews = resolveImageViews;
286 }
287
getImageForCopy() const288 vk::ImageHelper &RenderTargetVk::getImageForCopy() const
289 {
290 ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
291 return *getOwnerOfData();
292 }
293
getImageForWrite() const294 vk::ImageHelper &RenderTargetVk::getImageForWrite() const
295 {
296 ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
297 return *getOwnerOfData();
298 }
299
flushStagedUpdates(ContextVk * contextVk,vk::ClearValuesArray * deferredClears,uint32_t deferredClearIndex,uint32_t framebufferLayerCount)300 angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk,
301 vk::ClearValuesArray *deferredClears,
302 uint32_t deferredClearIndex,
303 uint32_t framebufferLayerCount)
304 {
305 ASSERT(mImage->valid() && (!isResolveImageOwnerOfData() || mResolveImage->valid()));
306 ASSERT(framebufferLayerCount != 0);
307
308 // It's impossible to defer clears to slices of a 3D images, as the clear applies to all the
309 // slices, while deferred clears only clear a single slice (where the framebuffer is attached).
310 // Additionally, the layer index for 3D textures is always zero according to Vulkan.
311 uint32_t layerIndex = mLayerIndex;
312 if (mImage->getType() == VK_IMAGE_TYPE_3D)
313 {
314 layerIndex = 0;
315 deferredClears = nullptr;
316 deferredClearIndex = 0;
317 }
318
319 vk::ImageHelper *image = getOwnerOfData();
320
321 // All updates should be staged on the image that owns the data as the source of truth. With
322 // multisampled-render-to-texture framebuffers, that is the resolve image. In that case, even
323 // though deferred clears set the loadOp of the transient multisampled image, the clears
324 // themselves are staged on the resolve image. The |flushSingleSubresourceStagedUpdates| call
325 // below will either flush all staged updates to the resolve image, or if the only staged update
326 // is a clear, it will accumulate it in the |deferredClears| array. Later, when the render pass
327 // is started, the deferred clears are applied to the transient multisampled image.
328 ASSERT(!isResolveImageOwnerOfData() ||
329 !mImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
330 ASSERT(isResolveImageOwnerOfData() || mResolveImage == nullptr ||
331 !mResolveImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
332
333 if (!image->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, framebufferLayerCount))
334 {
335 return angle::Result::Continue;
336 }
337
338 return image->flushSingleSubresourceStagedUpdates(contextVk, mLevelIndexGL, layerIndex,
339 framebufferLayerCount, deferredClears,
340 deferredClearIndex);
341 }
342
hasDefinedContent() const343 bool RenderTargetVk::hasDefinedContent() const
344 {
345 vk::ImageHelper *image = getOwnerOfData();
346 return image->hasSubresourceDefinedContent(mLevelIndexGL, mLayerIndex, mLayerCount);
347 }
348
hasDefinedStencilContent() const349 bool RenderTargetVk::hasDefinedStencilContent() const
350 {
351 vk::ImageHelper *image = getOwnerOfData();
352 return image->hasSubresourceDefinedStencilContent(mLevelIndexGL, mLayerIndex, mLayerCount);
353 }
354
invalidateEntireContent(ContextVk * contextVk,bool * preferToKeepContentsDefinedOut)355 void RenderTargetVk::invalidateEntireContent(ContextVk *contextVk,
356 bool *preferToKeepContentsDefinedOut)
357 {
358 vk::ImageHelper *image = getOwnerOfData();
359 image->invalidateSubresourceContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount,
360 preferToKeepContentsDefinedOut);
361 }
362
invalidateEntireStencilContent(ContextVk * contextVk,bool * preferToKeepContentsDefinedOut)363 void RenderTargetVk::invalidateEntireStencilContent(ContextVk *contextVk,
364 bool *preferToKeepContentsDefinedOut)
365 {
366 vk::ImageHelper *image = getOwnerOfData();
367 image->invalidateSubresourceStencilContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount,
368 preferToKeepContentsDefinedOut);
369 }
370
getImageIndexForClear(uint32_t layerCount) const371 gl::ImageIndex RenderTargetVk::getImageIndexForClear(uint32_t layerCount) const
372 {
373 // Determine the GL type from the Vk Image properties.
374 if (mImage->getType() == VK_IMAGE_TYPE_3D || mImage->getLayerCount() > 1)
375 {
376 // This is used for the sake of staging clears. The depth slices of the 3D image are
377 // threated as layers for this purpose.
378 //
379 // We also don't need to distinguish 2D array and cube.
380 return gl::ImageIndex::Make2DArrayRange(mLevelIndexGL.get(), mLayerIndex, layerCount);
381 }
382
383 ASSERT(mLayerIndex == 0);
384 ASSERT(mLayerCount == 1);
385 ASSERT(layerCount == 1);
386 return gl::ImageIndex::Make2D(mLevelIndexGL.get());
387 }
388 } // namespace rx
389