Hash :
74816e9e
Author :
Date :
2024-08-29T15:58:22
Vulkan: Cleanup RenderTargetVk release/destroy methods Current implementation of `release()` and `destroy()` methods does not actually invalidate state of the object. All they do is manage the Framebuffer cache. The `release()` method renamed to `releaseFramebuffers()` to match its behavior. Added new `releaseImageAndViews()` method that calls `releaseFramebuffers()` and also null the pointers in order to catch invalid usage in ASSSERTs (for example: usage of `SurfaceVk::mColorRenderTarget` after swapchain recreation but before ANI processing). `destroy()` is updated to also call `reset()`. `releaseFramebuffers()` is only used in `TextureVk` class. In case of `releaseImageViews()`, arrays are cleared, so there is no point calling `releaseImageAndViews()`. In case of `refreshImageViews()`, render targets may be reused, since all pointers remain valid. `RenderbufferVk` and `WindowSurfaceVk` are using new `releaseImageAndViews()` and updated `destroy()` methods. Other changes: - Replace clearing of RT arrays in `TextureVk::setImageHelper()` with ASSERTs. - Fix ASSERT in `TextureVk::releaseImageViews()`, but it seems that this code path is impossible. Bug: b/234769934 Change-Id: I431d25b81dd4dd343149c12e680e5c997aa18436 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5822575 Reviewed-by: Charlie Lao <cclao@google.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Igor Nazarov <i.nazarov@samsung.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// RenderTargetVk:
// Wrapper around a Vulkan renderable resource, using an ImageView.
//
#ifndef LIBANGLE_RENDERER_VULKAN_RENDERTARGETVK_H_
#define LIBANGLE_RENDERER_VULKAN_RENDERTARGETVK_H_
#include "common/vulkan/vk_headers.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/renderer/renderer_utils.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
namespace rx
{
namespace vk
{
class FramebufferHelper;
class ImageHelper;
class ImageView;
class Resource;
class RenderPassDesc;
} // namespace vk
class ContextVk;
class TextureVk;
enum class RenderTargetTransience
{
// Regular render targets that load and store from the image.
Default,
// Multisampled-render-to-texture textures, where the implicit multisampled image is transient,
// but the resolved image is persistent.
MultisampledTransient,
// Renderable YUV textures, where the color attachment (if it exists at all) is transient,
// but the resolved image is persistent.
YuvResolveTransient,
// Multisampled-render-to-texture depth/stencil textures.
EntirelyTransient,
};
// This is a very light-weight class that does not own to the resources it points to.
// It's meant only to copy across some information from a FramebufferAttachment to the
// business rendering logic. It stores Images and ImageViews by pointer for performance.
class RenderTargetVk final : public FramebufferAttachmentRenderTarget
{
public:
RenderTargetVk();
~RenderTargetVk() override;
// Used in std::vector initialization.
RenderTargetVk(RenderTargetVk &&other);
void 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);
vk::ImageOrBufferViewSubresourceSerial getDrawSubresourceSerial() const;
vk::ImageOrBufferViewSubresourceSerial getResolveSubresourceSerial() const;
// Note: RenderTargets should be called in order, with the depth/stencil onRender last.
void onColorDraw(ContextVk *contextVk,
uint32_t framebufferLayerCount,
vk::PackedAttachmentIndex index);
void onColorResolve(ContextVk *contextVk,
uint32_t framebufferLayerCount,
size_t readColorIndexGL,
const vk::ImageView &view);
void onDepthStencilDraw(ContextVk *contextVk, uint32_t framebufferLayerCount);
void onDepthStencilResolve(ContextVk *contextVk,
uint32_t framebufferLayerCount,
VkImageAspectFlags aspects,
const vk::ImageView &view);
vk::ImageHelper &getImageForRenderPass();
const vk::ImageHelper &getImageForRenderPass() const;
vk::ImageHelper &getResolveImageForRenderPass();
const vk::ImageHelper &getResolveImageForRenderPass() const;
vk::ImageHelper &getImageForCopy() const;
vk::ImageHelper &getImageForWrite() const;
// For cube maps we use single-level single-layer 2D array views.
angle::Result getImageView(vk::Context *context, const vk::ImageView **imageViewOut) const;
angle::Result getImageViewWithColorspace(vk::Context *context,
gl::SrgbWriteControlMode srgbWriteContrlMode,
const vk::ImageView **imageViewOut) const;
angle::Result getResolveImageView(vk::Context *context,
const vk::ImageView **imageViewOut) const;
// For 3D textures, the 2D view created for render target is invalid to read from. The
// following will return a view to the whole image (for all types, including 3D and 2DArray).
angle::Result getCopyImageView(vk::Context *context, const vk::ImageView **imageViewOut) const;
angle::FormatID getImageActualFormatID() const;
const angle::Format &getImageActualFormat() const;
angle::FormatID getImageIntendedFormatID() const;
const angle::Format &getImageIntendedFormat() const;
gl::Extents getExtents() const;
gl::Extents getRotatedExtents() const;
gl::LevelIndex getLevelIndex() const { return mLevelIndexGL; }
gl::LevelIndex getLevelIndexForImage(const vk::ImageHelper &image) const;
uint32_t getLayerIndex() const { return mLayerIndex; }
uint32_t getLayerCount() const { return mLayerCount; }
bool is3DImage() const { return getOwnerOfData()->getType() == VK_IMAGE_TYPE_3D; }
gl::ImageIndex getImageIndexForClear(uint32_t layerCount) const;
// Special mutator for Surface RenderTargets. Allows the Framebuffer to keep a single
// RenderTargetVk pointer.
void updateSwapchainImage(vk::ImageHelper *image,
vk::ImageViewHelper *imageViews,
vk::ImageHelper *resolveImage,
vk::ImageViewHelper *resolveImageViews);
angle::Result flushStagedUpdates(ContextVk *contextVk,
vk::ClearValuesArray *deferredClears,
uint32_t deferredClearIndex,
uint32_t framebufferLayerCount);
bool hasDefinedContent() const;
bool hasDefinedStencilContent() const;
// Mark content as undefined so that certain optimizations are possible such as using DONT_CARE
// as loadOp of the render target in the next renderpass. If |preferToKeepContentsDefinedOut|
// is set to true, it's preferred to ignore the invalidation due to image format and device
// architecture properties.
void invalidateEntireContent(ContextVk *contextVk, bool *preferToKeepContentsDefinedOut);
void invalidateEntireStencilContent(ContextVk *contextVk, bool *preferToKeepContentsDefinedOut);
// See the description of mTransience for details of how the following two can interact.
bool hasResolveAttachment() const { return mResolveImage != nullptr && !isEntirelyTransient(); }
bool isImageTransient() const { return mTransience != RenderTargetTransience::Default; }
bool isEntirelyTransient() const
{
return mTransience == RenderTargetTransience::EntirelyTransient;
}
bool isYuvResolve() const
{
return mResolveImage != nullptr ? mResolveImage->isYuvResolve() : false;
}
void onNewFramebuffer(const vk::SharedFramebufferCacheKey &sharedFramebufferCacheKey)
{
ASSERT(!mFramebufferCacheManager.containsKey(sharedFramebufferCacheKey));
mFramebufferCacheManager.addKey(sharedFramebufferCacheKey);
}
void releaseFramebuffers(ContextVk *contextVk)
{
mFramebufferCacheManager.releaseKeys(contextVk);
}
// Releases framebuffers and resets Image and ImageView pointers, while keeping other
// members intact, in order to allow |updateSwapchainImage| call later.
void releaseImageAndViews(ContextVk *contextVk)
{
releaseFramebuffers(contextVk);
invalidateImageAndViews();
}
// Releases framebuffers and resets all members to the initial state.
void destroy(vk::Renderer *renderer)
{
mFramebufferCacheManager.destroyKeys(renderer);
reset();
}
private:
void invalidateImageAndViews();
void reset();
angle::Result getImageViewImpl(vk::Context *context,
const vk::ImageHelper &image,
gl::SrgbWriteControlMode mode,
vk::ImageViewHelper *imageViews,
const vk::ImageView **imageViewOut) const;
vk::ImageOrBufferViewSubresourceSerial getSubresourceSerialImpl(
vk::ImageViewHelper *imageViews) const;
bool isResolveImageOwnerOfData() const;
vk::ImageHelper *getOwnerOfData() const;
// The color or depth/stencil attachment of the framebuffer and its view.
vk::ImageHelper *mImage;
vk::ImageViewHelper *mImageViews;
// If present, this is the corresponding resolve attachment and its view. This is used to
// implement GL_EXT_multisampled_render_to_texture, so while the rendering is done on mImage
// during the renderpass, the resolved image is the one that actually holds the data. This
// means that data uploads and blit are done on this image, copies are done out of this image
// etc. This means that if there is no clear, and hasDefined*Content(), the contents of
// mResolveImage must be copied to mImage since the loadOp of the attachment must be set to
// LOAD.
vk::ImageHelper *mResolveImage;
vk::ImageViewHelper *mResolveImageViews;
UniqueSerial mImageSiblingSerial;
// Which subresource of the image is used as render target.
//
// |mLevelIndexGL| applies to the level index of mImage unless there is a resolve attachment,
// in which case |mLevelIndexGL| applies to the mResolveImage since mImage is always
// single-level.
//
// For single-layer render targets, |mLayerIndex| will contain the layer index and |mLayerCount|
// will be 1. For layered render targets, |mLayerIndex| will be 0 and |mLayerCount| will be the
// number of layers in the image (or level depth, if image is 3D). Note that blit and other
// functions that read or write to the render target always use layer 0, so this works out for
// users of |getLayerIndex()|.
gl::LevelIndex mLevelIndexGL;
uint32_t mLayerIndex;
uint32_t mLayerCount;
// If resolve attachment exists, |mTransience| could be *Transient if the multisampled results
// need to be discarded.
//
// - GL_EXT_multisampled_render_to_texture[2]: this is |MultisampledTransient| for render
// targets created from color textures, as well as color or depth/stencil renderbuffers.
// - GL_EXT_multisampled_render_to_texture2: this is |EntirelyTransient| for depth/stencil
// textures per this extension, even though a resolve attachment is not even provided.
//
// Based on the above, we have:
//
// mResolveImage == nullptr
// Normal rendering
// Default No resolve
// storeOp = STORE
// Owner of data: mImage
//
// ---------------------------------------------
//
// mResolveImage != nullptr
// GL_EXT_multisampled_render_to_texture
// Multisampled Resolve
// Transient storeOp = DONT_CARE
// resolve storeOp = STORE
// Owner of data: mResolveImage
//
// ---------------------------------------------
//
// mResolveImage != nullptr
// GL_EXT_multisampled_render_to_texture2
// Entirely No Resolve
// Transient storeOp = DONT_CARE
// Owner of data: mResolveImage
//
// In the above, storeOp of the resolve attachment is always STORE. If |Default|, storeOp is
// affected by a framebuffer invalidate call. Note that even though |EntirelyTransient| has a
// resolve attachment, it is not used. The only purpose of |mResolveImage| is to store deferred
// clears.
RenderTargetTransience mTransience;
// Track references to the cached Framebuffer object that created out of this object
vk::FramebufferCacheManager mFramebufferCacheManager;
};
// A vector of rendertargets
using RenderTargetVector = std::vector<RenderTargetVk>;
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_RENDERTARGETVK_H_