Hash :
20e7bbb7
Author :
Date :
2022-03-18T17:03:18
Vulkan: Fix invalidate of attachments with emulated format Some image formats may be emulated such that the emulated format has more channels than the original. ANGLE clears the image once so that these extra channels contain valid values, and carefully ensures they are never modified. For swapchain images with such formats, as they are automatically invalidated at the end of the frame, a workaroud was added to make sure they are re-cleared in the beginning of the next frame. This however doesn't fix the issue of glInvalidateFramebuffer resulting in the contents of attachments with such formats to be discarded (even if the following render pass clears it, the contents are invalid in between). This change instead makes sure invalidate of images with emulated formats that have extra channels are handled appropriately: - On IMR hardware, the invalidate is dropped altogether as it provides little to no benefit. - On TBR hardware, a clear is automatically staged on the invalidated image. The latter replaces the workaround that was added to make the following render pass use loadOp=CLEAR, by adding a clear that's respected regardless of what the future usage is. This change also paves the way for a future change where the invalidate of color attachments is tracked in render passes similarly to how depth/stencil currently is. With this change, the image is no longer in an inconsistent state where its contents are considered invalid, even though some channels are meant to remain valid. Bug: angleproject:6860 Change-Id: Iec5b4854dfbe3a0bf93cd5aa82c19fe116065744 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3536389 Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Charlie Lao <cclao@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
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
//
// 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,
// 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,
gl::LevelIndex levelIndexGL,
uint32_t layerIndex,
uint32_t layerCount,
RenderTargetTransience transience);
void reset();
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);
void onDepthStencilDraw(ContextVk *contextVk, uint32_t framebufferLayerCount);
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 *contextVk, 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; }
uint32_t getLayerIndex() const { return mLayerIndex; }
uint32_t getLayerCount() const { return mLayerCount; }
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;
}
private:
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;
// Which subresource of the image is used as render target. 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;
};
// A vector of rendertargets
using RenderTargetVector = std::vector<RenderTargetVk>;
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_RENDERTARGETVK_H_