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->getActualFormat().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->getActualFormat().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->getActualFormat();
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
getImageActualFormatID() const240 angle::FormatID RenderTargetVk::getImageActualFormatID() const
241 {
242 ASSERT(mImage && mImage->valid());
243 return mImage->getActualFormatID();
244 }
245
getImageIntendedFormatID() const246 angle::FormatID RenderTargetVk::getImageIntendedFormatID() const
247 {
248 ASSERT(mImage && mImage->valid());
249 return mImage->getIntendedFormatID();
250 }
251
getImageActualFormat() const252 const angle::Format &RenderTargetVk::getImageActualFormat() const
253 {
254 ASSERT(mImage && mImage->valid());
255 return mImage->getActualFormat();
256 }
257
getImageIntendedFormat() const258 const angle::Format &RenderTargetVk::getImageIntendedFormat() const
259 {
260 ASSERT(mImage && mImage->valid());
261 return mImage->getIntendedFormat();
262 }
263
getExtents() const264 gl::Extents RenderTargetVk::getExtents() const
265 {
266 ASSERT(mImage && mImage->valid());
267 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
268 return mImage->getLevelExtents2D(levelVk);
269 }
270
getRotatedExtents() const271 gl::Extents RenderTargetVk::getRotatedExtents() const
272 {
273 ASSERT(mImage && mImage->valid());
274 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
275 return mImage->getRotatedLevelExtents2D(levelVk);
276 }
277
updateSwapchainImage(vk::ImageHelper * image,vk::ImageViewHelper * imageViews,vk::ImageHelper * resolveImage,vk::ImageViewHelper * resolveImageViews)278 void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image,
279 vk::ImageViewHelper *imageViews,
280 vk::ImageHelper *resolveImage,
281 vk::ImageViewHelper *resolveImageViews)
282 {
283 ASSERT(image && image->valid() && imageViews);
284 mImage = image;
285 mImageViews = imageViews;
286 mResolveImage = resolveImage;
287 mResolveImageViews = resolveImageViews;
288 }
289
getImageForCopy() const290 vk::ImageHelper &RenderTargetVk::getImageForCopy() const
291 {
292 ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
293 return *getOwnerOfData();
294 }
295
getImageForWrite() const296 vk::ImageHelper &RenderTargetVk::getImageForWrite() const
297 {
298 ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
299 return *getOwnerOfData();
300 }
301
flushStagedUpdates(ContextVk * contextVk,vk::ClearValuesArray * deferredClears,uint32_t deferredClearIndex,uint32_t framebufferLayerCount)302 angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk,
303 vk::ClearValuesArray *deferredClears,
304 uint32_t deferredClearIndex,
305 uint32_t framebufferLayerCount)
306 {
307 ASSERT(mImage->valid() && (!isResolveImageOwnerOfData() || mResolveImage->valid()));
308 ASSERT(framebufferLayerCount != 0);
309
310 // It's impossible to defer clears to slices of a 3D images, as the clear applies to all the
311 // slices, while deferred clears only clear a single slice (where the framebuffer is attached).
312 // Additionally, the layer index for 3D textures is always zero according to Vulkan.
313 uint32_t layerIndex = mLayerIndex;
314 if (mImage->getType() == VK_IMAGE_TYPE_3D)
315 {
316 layerIndex = 0;
317 deferredClears = nullptr;
318 deferredClearIndex = 0;
319 }
320
321 vk::ImageHelper *image = getOwnerOfData();
322
323 // All updates should be staged on the image that owns the data as the source of truth. With
324 // multisampled-render-to-texture framebuffers, that is the resolve image. In that case, even
325 // though deferred clears set the loadOp of the transient multisampled image, the clears
326 // themselves are staged on the resolve image. The |flushSingleSubresourceStagedUpdates| call
327 // below will either flush all staged updates to the resolve image, or if the only staged update
328 // is a clear, it will accumulate it in the |deferredClears| array. Later, when the render pass
329 // is started, the deferred clears are applied to the transient multisampled image.
330 ASSERT(!isResolveImageOwnerOfData() ||
331 !mImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
332 ASSERT(isResolveImageOwnerOfData() || mResolveImage == nullptr ||
333 !mResolveImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
334
335 if (!image->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, framebufferLayerCount))
336 {
337 return angle::Result::Continue;
338 }
339
340 return image->flushSingleSubresourceStagedUpdates(contextVk, mLevelIndexGL, layerIndex,
341 framebufferLayerCount, deferredClears,
342 deferredClearIndex);
343 }
344
retainImageViews(ContextVk * contextVk) const345 void RenderTargetVk::retainImageViews(ContextVk *contextVk) const
346 {
347 mImageViews->retain(&contextVk->getResourceUseList());
348 if (mResolveImageViews)
349 {
350 mResolveImageViews->retain(&contextVk->getResourceUseList());
351 }
352 }
353
hasDefinedContent() const354 bool RenderTargetVk::hasDefinedContent() const
355 {
356 vk::ImageHelper *image = getOwnerOfData();
357 return image->hasSubresourceDefinedContent(mLevelIndexGL, mLayerIndex, mLayerCount);
358 }
359
hasDefinedStencilContent() const360 bool RenderTargetVk::hasDefinedStencilContent() const
361 {
362 vk::ImageHelper *image = getOwnerOfData();
363 return image->hasSubresourceDefinedStencilContent(mLevelIndexGL, mLayerIndex, mLayerCount);
364 }
365
invalidateEntireContent(ContextVk * contextVk)366 void RenderTargetVk::invalidateEntireContent(ContextVk *contextVk)
367 {
368 vk::ImageHelper *image = getOwnerOfData();
369 image->invalidateSubresourceContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount);
370 }
371
invalidateEntireStencilContent(ContextVk * contextVk)372 void RenderTargetVk::invalidateEntireStencilContent(ContextVk *contextVk)
373 {
374 vk::ImageHelper *image = getOwnerOfData();
375 image->invalidateSubresourceStencilContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount);
376 }
377
restoreEntireContent()378 void RenderTargetVk::restoreEntireContent()
379 {
380 vk::ImageHelper *image = getOwnerOfData();
381 image->restoreSubresourceContent(mLevelIndexGL, mLayerIndex, mLayerCount);
382 }
383
restoreEntireStencilContent()384 void RenderTargetVk::restoreEntireStencilContent()
385 {
386 vk::ImageHelper *image = getOwnerOfData();
387 image->restoreSubresourceStencilContent(mLevelIndexGL, mLayerIndex, mLayerCount);
388 }
389
getImageIndexForClear(uint32_t layerCount) const390 gl::ImageIndex RenderTargetVk::getImageIndexForClear(uint32_t layerCount) const
391 {
392 // Determine the GL type from the Vk Image properties.
393 if (mImage->getType() == VK_IMAGE_TYPE_3D || mImage->getLayerCount() > 1)
394 {
395 // This is used for the sake of staging clears. The depth slices of the 3D image are
396 // threated as layers for this purpose.
397 //
398 // We also don't need to distinguish 2D array and cube.
399 return gl::ImageIndex::Make2DArrayRange(mLevelIndexGL.get(), mLayerIndex, layerCount);
400 }
401
402 ASSERT(mLayerIndex == 0);
403 ASSERT(mLayerCount == 1);
404 ASSERT(layerCount == 1);
405 return gl::ImageIndex::Make2D(mLevelIndexGL.get());
406 }
407 } // namespace rx
408