blob: f60b9d632b3ec201c1668cab7730005bc873001e [file] [log] [blame]
// Copyright 2022 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "host/vulkan/emulated_textures/AstcTexture.h"
#include "vulkan/cereal/common/goldfish_vk_dispatch.h"
#include "vulkan/vulkan.h"
namespace gfxstream {
namespace vk {
class CompressedImageInfo {
public:
// Static methods
static VkFormat getDecompressedFormat(VkFormat compFmt);
// Returns the image format used to store the compressed data. Each pixel in the compressed
// mipmaps will hold an entire compressed block.
static VkFormat getCompressedMipmapsFormat(VkFormat compFmt);
static bool isEtc2(VkFormat format);
static bool isAstc(VkFormat format);
static bool needEmulatedAlpha(VkFormat format);
// Returns a VkImageCopy to copy to/from the compressed data
static VkImageCopy getCompressedMipmapsImageCopy(const VkImageCopy& origRegion,
const CompressedImageInfo& srcImg,
const CompressedImageInfo& dstImg,
bool needEmulatedSrc, bool needEmulatedDst);
// Constructors
// TODO(gregschlom) Delete these constructors once we switch to holding a
// std::unique_ptr<CompressedImageInfo>
CompressedImageInfo() = default;
explicit CompressedImageInfo(VkDevice device);
CompressedImageInfo(VkDevice device, const VkImageCreateInfo& createInfo);
// Public methods
// Returns the VkImageCreateInfo needed to create the decompressed image
VkImageCreateInfo getDecompressedCreateInfo(const VkImageCreateInfo& createInfo) const;
// Creates the compressed mipmap images, that is the VkImages holding the compressed data
void createCompressedMipmapImages(VulkanDispatch* vk, const VkImageCreateInfo& createInfo);
// Initializes the resources needed to perform CPU decompression of ASTC textures
void initAstcCpuDecompression(VulkanDispatch* vk, VkPhysicalDevice physicalDevice);
// Should be called when the guest calls vkCmdPipelineBarrier.
// This function checks if the image barrier transitions the compressed image to a layout where
// it will be read from, and if so, it decompresses the image.
//
// outputBarriers: any barrier that needs to be passed to the vkCmdPipelineBarrier call will be
// added to this vector.
// Returns whether image decompression happened.
bool decompressIfNeeded(VulkanDispatch* vk, VkCommandBuffer commandBuffer,
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
const VkImageMemoryBarrier& targetBarrier,
std::vector<VkImageMemoryBarrier>& outputBarriers);
void decompressOnCpu(VkCommandBuffer commandBuffer, uint8_t* srcAstcData, size_t astcDataSize,
VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
const VkBufferImageCopy* pRegions, const VkDecoderContext& context);
VkMemoryRequirements getMemoryRequirements() const;
VkResult bindCompressedMipmapsMemory(VulkanDispatch* vk, VkDeviceMemory memory,
VkDeviceSize memoryOffset);
// Given a VkBufferImageCopy object for the original image, returns a new
// VkBufferImageCopy that points to the same location in the compressed mipmap images.
VkBufferImageCopy getBufferImageCopy(const VkBufferImageCopy& origRegion) const;
// Releases all the resources used by this class. It may no longer be used after calling this.
void destroy(VulkanDispatch* vk);
// Accessors
bool isEtc2() const;
bool isAstc() const;
VkDevice device() const { return mDevice; }
VkImage compressedMipmap(uint32_t level) { return mCompressedMipmaps[level]; }
VkImage decompressedImage() { return mDecompressedImage; }
void setDecompressedImage(VkImage image) { mDecompressedImage = image; }
bool canDecompressOnCpu() { return mAstcTexture && mAstcTexture->canDecompressOnCpu(); }
bool successfullyDecompressedOnCpu() const {
return mAstcTexture && mAstcTexture->successfullyDecompressed();
}
private:
// Returns the size in bytes needed for the storage of a given image.
// Also updates the alignment field of this class.
VkDeviceSize getImageSize(VulkanDispatch* vk, VkImage image);
// Returns a vector of image barriers for the compressed mipmap images and the decompressed
// image.
std::vector<VkImageMemoryBarrier> getImageBarriers(const VkImageMemoryBarrier& srcBarrier);
VkImageSubresourceRange getImageSubresourceRange(const VkImageSubresourceRange& range) const;
// Initializes the compute shader pipeline to decompress the image.
// No-op if this was already called successfully.
VkResult initializeDecompressionPipeline(VulkanDispatch* vk, VkDevice device);
// Runs the decompression shader
void decompress(VulkanDispatch* vk, VkCommandBuffer commandBuffer,
const VkImageSubresourceRange& range);
// Returns the size of the image at a given mip level
VkExtent3D mipmapExtent(uint32_t level) const;
// Returns the size of the compressed mipmaps at a given mip level. This is mipmapExtent divided
// by the block size, and rounded up.
VkExtent3D compressedMipmapExtent(uint32_t level) const;
// Returns an extent into the compressed mipmaps. This divides the components of origExtent by
// the block size, and the result is clamped to not exceed the compressed mipmap size.
VkExtent3D compressedMipmapPortion(const VkExtent3D& origExtent, uint32_t level) const;
// Member variables
// The original compressed format of this image. E.g.: VK_FORMAT_ASTC_4x4_UNORM_BLOCK
VkFormat mCompressedFormat = VK_FORMAT_UNDEFINED;
// The format that we decompressed the image to. E.g.: VK_FORMAT_R8G8B8A8_UINT
VkFormat mDecompressedFormat = VK_FORMAT_UNDEFINED;
// The format that we use to store the compressed data, since the original compressed format
// isn't available. This holds one compressed block per pixel. E.g.: VK_FORMAT_R32G32B32A32_UINT
VkFormat mCompressedMipmapsFormat = VK_FORMAT_UNDEFINED;
VkImageType mImageType = VK_IMAGE_TYPE_MAX_ENUM;
uint32_t mMipLevels = 1; // Number of mip levels in the image
VkExtent3D mExtent = {}; // Size of the image
VkExtent2D mBlock = {1, 1}; // Size of the compressed blocks
uint32_t mLayerCount = 1;
VkDevice mDevice = VK_NULL_HANDLE;
VkImage mDecompressedImage = VK_NULL_HANDLE;
// Compressed data. Each mip level of the original image is stored as a separate VkImage, and
// each pixel in those images contains an entire compressed block.
std::vector<VkImage> mCompressedMipmaps;
VkDeviceSize mAlignment = 0;
std::vector<VkDeviceSize> mMemoryOffsets;
// Used to perform CPU decompression of ASTC textures. Null for non-ASTC images.
std::unique_ptr<AstcTexture> mAstcTexture = nullptr;
// Vulkan resources used by the decompression pipeline
VkShaderModule mDecompShader = VK_NULL_HANDLE;
VkPipeline mDecompPipeline = VK_NULL_HANDLE;
VkPipelineLayout mDecompPipelineLayout = VK_NULL_HANDLE;
std::vector<VkDescriptorSet> mDecompDescriptorSets;
VkDescriptorSetLayout mDecompDescriptorSetLayout = VK_NULL_HANDLE;
VkDescriptorPool mDecompDescriptorPool = VK_NULL_HANDLE;
std::vector<VkImageView> mCompressedMipmapsImageViews;
std::vector<VkImageView> mDecompImageViews;
};
} // namespace vk
} // namespace gfxstream