blob: 145100fbd394c50d4d982f57bf3f5ae454bc3c4a [file] [log] [blame]
//
// 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::ErrorContext *context, const vk::ImageView **imageViewOut) const;
angle::Result getImageViewWithColorspace(vk::ErrorContext *context,
gl::SrgbWriteControlMode srgbWriteContrlMode,
const vk::ImageView **imageViewOut) const;
angle::Result getResolveImageView(vk::ErrorContext *context,
const vk::ImageView **imageViewOut) const;
angle::Result getDepthOrStencilImageView(vk::ErrorContext *context,
VkImageAspectFlagBits aspect,
const vk::ImageView **imageViewOut) const;
angle::Result getDepthOrStencilImageViewForCopy(vk::ErrorContext *context,
VkImageAspectFlagBits aspect,
const vk::ImageView **imageViewOut) const;
angle::Result getResolveDepthOrStencilImageView(vk::ErrorContext *context,
VkImageAspectFlagBits aspect,
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::ErrorContext *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)
{
mFramebufferCacheManager.addKey(sharedFramebufferCacheKey);
}
void releaseFramebuffers(ContextVk *contextVk)
{
mFramebufferCacheManager.releaseKeys(contextVk);
}
// Resets all members to the initial state without releasing framebuffers since Window Surface
// framebuffers are not managed by the cache.
void releaseSwapchainImage() { reset(); }
// Releases framebuffers and resets all members to the initial state.
void release(ContextVk *contextVk)
{
releaseFramebuffers(contextVk);
reset();
}
// Destroys framebuffers and resets all members to the initial state.
void destroy(vk::Renderer *renderer)
{
mFramebufferCacheManager.destroyKeys(renderer);
reset();
}
// Helpers to update rendertarget colorspace
void updateWriteColorspace(gl::SrgbWriteControlMode srgbWriteControlMode)
{
ASSERT(mImage && mImage->valid() && mImageViews);
mImageViews->updateSrgbWiteControlMode(*mImage, srgbWriteControlMode);
}
bool hasColorspaceOverrideForRead() const
{
ASSERT(mImage && mImage->valid() && mImageViews);
return mImageViews->hasColorspaceOverrideForRead(*mImage);
}
bool hasColorspaceOverrideForWrite() const
{
ASSERT(mImage && mImage->valid() && mImageViews);
return mImageViews->hasColorspaceOverrideForWrite(*mImage);
}
angle::FormatID getColorspaceOverrideFormatForWrite(angle::FormatID format) const
{
ASSERT(mImage && mImage->valid() && mImageViews);
return mImageViews->getColorspaceOverrideFormatForWrite(format);
}
private:
void reset();
angle::Result getImageViewImpl(vk::ErrorContext *context,
const vk::ImageHelper &image,
vk::ImageViewHelper *imageViews,
const vk::ImageView **imageViewOut) const;
angle::Result getDepthOrStencilImageViewImpl(vk::ErrorContext *context,
const vk::ImageHelper &image,
vk::ImageViewHelper *imageViews,
VkImageAspectFlagBits aspect,
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_