180 lines
8.1 KiB
C
180 lines
8.1 KiB
C
|
|
// 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 "stream-servers/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
|