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(mLevelIndexGL, mLayerIndex, framebufferLayerCount, mImage, mResolveImage,
102 packedAttachmentIndex);
103
104 // Multisampled render to texture framebuffers cannot be layered.
105 ASSERT(mResolveImage == nullptr || framebufferLayerCount == 1);
106 }
107
onColorResolve(ContextVk * contextVk,uint32_t framebufferLayerCount)108 void RenderTargetVk::onColorResolve(ContextVk *contextVk, uint32_t framebufferLayerCount)
109 {
110 ASSERT(!mImage->getActualFormat().hasDepthOrStencilBits());
111 ASSERT(framebufferLayerCount <= mLayerCount);
112 ASSERT(mResolveImage == nullptr);
113
114 contextVk->onImageRenderPassWrite(mLevelIndexGL, mLayerIndex, framebufferLayerCount,
115 VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment,
116 mImage);
117 }
118
onDepthStencilDraw(ContextVk * contextVk,uint32_t framebufferLayerCount)119 void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk, uint32_t framebufferLayerCount)
120 {
121 const angle::Format &format = mImage->getActualFormat();
122 ASSERT(format.hasDepthOrStencilBits());
123 ASSERT(framebufferLayerCount <= mLayerCount);
124
125 contextVk->onDepthStencilDraw(mLevelIndexGL, mLayerIndex, framebufferLayerCount, mImage,
126 mResolveImage);
127 }
128
getImageForRenderPass()129 vk::ImageHelper &RenderTargetVk::getImageForRenderPass()
130 {
131 ASSERT(mImage && mImage->valid());
132 return *mImage;
133 }
134
getImageForRenderPass() const135 const vk::ImageHelper &RenderTargetVk::getImageForRenderPass() const
136 {
137 ASSERT(mImage && mImage->valid());
138 return *mImage;
139 }
140
getResolveImageForRenderPass()141 vk::ImageHelper &RenderTargetVk::getResolveImageForRenderPass()
142 {
143 ASSERT(mResolveImage && mResolveImage->valid());
144 return *mResolveImage;
145 }
146
getResolveImageForRenderPass() const147 const vk::ImageHelper &RenderTargetVk::getResolveImageForRenderPass() const
148 {
149 ASSERT(mResolveImage && mResolveImage->valid());
150 return *mResolveImage;
151 }
152
getImageViewImpl(vk::Context * context,const vk::ImageHelper & image,gl::SrgbWriteControlMode mode,vk::ImageViewHelper * imageViews,const vk::ImageView ** imageViewOut) const153 angle::Result RenderTargetVk::getImageViewImpl(vk::Context *context,
154 const vk::ImageHelper &image,
155 gl::SrgbWriteControlMode mode,
156 vk::ImageViewHelper *imageViews,
157 const vk::ImageView **imageViewOut) const
158 {
159 ASSERT(image.valid() && imageViews);
160 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
161 if (mLayerCount == 1)
162 {
163 return imageViews->getLevelLayerDrawImageView(context, image, levelVk, mLayerIndex, mode,
164 imageViewOut);
165 }
166
167 // Layered render targets view the whole level or a handful of layers in case of multiview.
168 return imageViews->getLevelDrawImageView(context, image, levelVk, mLayerIndex, mLayerCount,
169 mode, imageViewOut);
170 }
171
getImageView(vk::Context * context,const vk::ImageView ** imageViewOut) const172 angle::Result RenderTargetVk::getImageView(vk::Context *context,
173 const vk::ImageView **imageViewOut) const
174 {
175 ASSERT(mImage);
176 return getImageViewImpl(context, *mImage, gl::SrgbWriteControlMode::Default, mImageViews,
177 imageViewOut);
178 }
179
getImageViewWithColorspace(vk::Context * context,gl::SrgbWriteControlMode mode,const vk::ImageView ** imageViewOut) const180 angle::Result RenderTargetVk::getImageViewWithColorspace(vk::Context *context,
181 gl::SrgbWriteControlMode mode,
182 const vk::ImageView **imageViewOut) const
183 {
184 ASSERT(mImage);
185 return getImageViewImpl(context, *mImage, mode, mImageViews, imageViewOut);
186 }
187
getResolveImageView(vk::Context * context,const vk::ImageView ** imageViewOut) const188 angle::Result RenderTargetVk::getResolveImageView(vk::Context *context,
189 const vk::ImageView **imageViewOut) const
190 {
191 ASSERT(mResolveImage);
192 return getImageViewImpl(context, *mResolveImage, gl::SrgbWriteControlMode::Default,
193 mResolveImageViews, imageViewOut);
194 }
195
isResolveImageOwnerOfData() const196 bool RenderTargetVk::isResolveImageOwnerOfData() const
197 {
198 // If there's a resolve attachment and the image itself is transient, it's the resolve
199 // attachment that owns the data, so all non-render-pass accesses to the render target data
200 // should go through the resolve attachment.
201 return isImageTransient();
202 }
203
getOwnerOfData() const204 vk::ImageHelper *RenderTargetVk::getOwnerOfData() const
205 {
206 return isResolveImageOwnerOfData() ? mResolveImage : mImage;
207 }
208
getCopyImageView(vk::Context * context,const vk::ImageView ** imageViewOut) const209 angle::Result RenderTargetVk::getCopyImageView(vk::Context *context,
210 const vk::ImageView **imageViewOut) const
211 {
212 const vk::ImageViewHelper *imageViews =
213 isResolveImageOwnerOfData() ? mResolveImageViews : mImageViews;
214
215 // If the source of render target is a texture or renderbuffer, this will always be valid. This
216 // is also where 3D or 2DArray images could be the source of the render target.
217 if (imageViews->hasCopyImageView())
218 {
219 *imageViewOut = &imageViews->getCopyImageView();
220 return angle::Result::Continue;
221 }
222
223 // Otherwise, this must come from the surface, in which case the image is 2D, so the image view
224 // used to draw is just as good for fetching. If resolve attachment is present, fetching is
225 // done from that.
226 return isResolveImageOwnerOfData() ? getResolveImageView(context, imageViewOut)
227 : getImageView(context, imageViewOut);
228 }
229
getImageActualFormatID() const230 angle::FormatID RenderTargetVk::getImageActualFormatID() const
231 {
232 ASSERT(mImage && mImage->valid());
233 return mImage->getActualFormatID();
234 }
235
getImageIntendedFormatID() const236 angle::FormatID RenderTargetVk::getImageIntendedFormatID() const
237 {
238 ASSERT(mImage && mImage->valid());
239 return mImage->getIntendedFormatID();
240 }
241
getImageActualFormat() const242 const angle::Format &RenderTargetVk::getImageActualFormat() const
243 {
244 ASSERT(mImage && mImage->valid());
245 return mImage->getActualFormat();
246 }
247
getImageIntendedFormat() const248 const angle::Format &RenderTargetVk::getImageIntendedFormat() const
249 {
250 ASSERT(mImage && mImage->valid());
251 return mImage->getIntendedFormat();
252 }
253
getExtents() const254 gl::Extents RenderTargetVk::getExtents() const
255 {
256 ASSERT(mImage && mImage->valid());
257 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
258 return mImage->getLevelExtents2D(levelVk);
259 }
260
getRotatedExtents() const261 gl::Extents RenderTargetVk::getRotatedExtents() const
262 {
263 ASSERT(mImage && mImage->valid());
264 vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
265 return mImage->getRotatedLevelExtents2D(levelVk);
266 }
267
updateSwapchainImage(vk::ImageHelper * image,vk::ImageViewHelper * imageViews,vk::ImageHelper * resolveImage,vk::ImageViewHelper * resolveImageViews)268 void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image,
269 vk::ImageViewHelper *imageViews,
270 vk::ImageHelper *resolveImage,
271 vk::ImageViewHelper *resolveImageViews)
272 {
273 ASSERT(image && image->valid() && imageViews);
274 mImage = image;
275 mImageViews = imageViews;
276 mResolveImage = resolveImage;
277 mResolveImageViews = resolveImageViews;
278 }
279
getImageForCopy() const280 vk::ImageHelper &RenderTargetVk::getImageForCopy() const
281 {
282 ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
283 return *getOwnerOfData();
284 }
285
getImageForWrite() const286 vk::ImageHelper &RenderTargetVk::getImageForWrite() const
287 {
288 ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
289 return *getOwnerOfData();
290 }
291
flushStagedUpdates(ContextVk * contextVk,vk::ClearValuesArray * deferredClears,uint32_t deferredClearIndex,uint32_t framebufferLayerCount)292 angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk,
293 vk::ClearValuesArray *deferredClears,
294 uint32_t deferredClearIndex,
295 uint32_t framebufferLayerCount)
296 {
297 ASSERT(mImage->valid() && (!isResolveImageOwnerOfData() || mResolveImage->valid()));
298 ASSERT(framebufferLayerCount != 0);
299
300 // It's impossible to defer clears to slices of a 3D images, as the clear applies to all the
301 // slices, while deferred clears only clear a single slice (where the framebuffer is attached).
302 // Additionally, the layer index for 3D textures is always zero according to Vulkan.
303 uint32_t layerIndex = mLayerIndex;
304 if (mImage->getType() == VK_IMAGE_TYPE_3D)
305 {
306 layerIndex = 0;
307 deferredClears = nullptr;
308 deferredClearIndex = 0;
309 }
310
311 vk::ImageHelper *image = getOwnerOfData();
312
313 // All updates should be staged on the image that owns the data as the source of truth. With
314 // multisampled-render-to-texture framebuffers, that is the resolve image. In that case, even
315 // though deferred clears set the loadOp of the transient multisampled image, the clears
316 // themselves are staged on the resolve image. The |flushSingleSubresourceStagedUpdates| call
317 // below will either flush all staged updates to the resolve image, or if the only staged update
318 // is a clear, it will accumulate it in the |deferredClears| array. Later, when the render pass
319 // is started, the deferred clears are applied to the transient multisampled image.
320 ASSERT(!isResolveImageOwnerOfData() ||
321 !mImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
322 ASSERT(isResolveImageOwnerOfData() || mResolveImage == nullptr ||
323 !mResolveImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
324
325 if (!image->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, framebufferLayerCount))
326 {
327 return angle::Result::Continue;
328 }
329
330 return image->flushSingleSubresourceStagedUpdates(contextVk, mLevelIndexGL, layerIndex,
331 framebufferLayerCount, deferredClears,
332 deferredClearIndex);
333 }
334
hasDefinedContent() const335 bool RenderTargetVk::hasDefinedContent() const
336 {
337 vk::ImageHelper *image = getOwnerOfData();
338 return image->hasSubresourceDefinedContent(mLevelIndexGL, mLayerIndex, mLayerCount);
339 }
340
hasDefinedStencilContent() const341 bool RenderTargetVk::hasDefinedStencilContent() const
342 {
343 vk::ImageHelper *image = getOwnerOfData();
344 return image->hasSubresourceDefinedStencilContent(mLevelIndexGL, mLayerIndex, mLayerCount);
345 }
346
invalidateEntireContent(ContextVk * contextVk,bool * preferToKeepContentsDefinedOut)347 void RenderTargetVk::invalidateEntireContent(ContextVk *contextVk,
348 bool *preferToKeepContentsDefinedOut)
349 {
350 vk::ImageHelper *image = getOwnerOfData();
351 image->invalidateSubresourceContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount,
352 preferToKeepContentsDefinedOut);
353 }
354
invalidateEntireStencilContent(ContextVk * contextVk,bool * preferToKeepContentsDefinedOut)355 void RenderTargetVk::invalidateEntireStencilContent(ContextVk *contextVk,
356 bool *preferToKeepContentsDefinedOut)
357 {
358 vk::ImageHelper *image = getOwnerOfData();
359 image->invalidateSubresourceStencilContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount,
360 preferToKeepContentsDefinedOut);
361 }
362
getImageIndexForClear(uint32_t layerCount) const363 gl::ImageIndex RenderTargetVk::getImageIndexForClear(uint32_t layerCount) const
364 {
365 // Determine the GL type from the Vk Image properties.
366 if (mImage->getType() == VK_IMAGE_TYPE_3D || mImage->getLayerCount() > 1)
367 {
368 // This is used for the sake of staging clears. The depth slices of the 3D image are
369 // threated as layers for this purpose.
370 //
371 // We also don't need to distinguish 2D array and cube.
372 return gl::ImageIndex::Make2DArrayRange(mLevelIndexGL.get(), mLayerIndex, layerCount);
373 }
374
375 ASSERT(mLayerIndex == 0);
376 ASSERT(mLayerCount == 1);
377 ASSERT(layerCount == 1);
378 return gl::ImageIndex::Make2D(mLevelIndexGL.get());
379 }
380 } // namespace rx
381