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