blob: 9f060db7f9d5c4d0b89d8965a4a0cf6ad012e062 [file] [log] [blame]
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/gpu/ganesh/vk/GrVkBackendSurface.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkTextureCompressionType.h"
#include "include/gpu/GpuTypes.h"
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrTypes.h"
#include "include/gpu/MutableTextureState.h"
#include "include/gpu/vk/GrVkTypes.h"
#include "include/gpu/vk/VulkanMutableTextureState.h"
#include "include/private/base/SkAssert.h"
#include "include/private/base/SkTo.h"
#include "include/private/gpu/ganesh/GrTypesPriv.h"
#include "src/gpu/ganesh/GrBackendSurfacePriv.h"
#include "src/gpu/ganesh/vk/GrVkTypesPriv.h"
#include "src/gpu/ganesh/vk/GrVkUtil.h"
#include "src/gpu/vk/VulkanMutableTextureStatePriv.h"
#include "src/gpu/vk/VulkanUtilsPriv.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <string>
class GrVkBackendFormatData final : public GrBackendFormatData {
public:
GrVkBackendFormatData(VkFormat format, const GrVkYcbcrConversionInfo& ycbcrInfo)
: fFormat(format), fYcbcrConversionInfo(ycbcrInfo) {}
VkFormat asVkFormat() const { return fFormat; }
const GrVkYcbcrConversionInfo* getYcbcrConversionInfo() const { return &fYcbcrConversionInfo; }
private:
SkTextureCompressionType compressionType() const override {
switch (fFormat) {
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
return SkTextureCompressionType::kETC2_RGB8_UNORM;
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
return SkTextureCompressionType::kBC1_RGB8_UNORM;
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
return SkTextureCompressionType::kBC1_RGBA8_UNORM;
default:
return SkTextureCompressionType::kNone;
}
}
size_t bytesPerBlock() const override {
return skgpu::VkFormatBytesPerBlock(fFormat);
}
int stencilBits() const override {
return skgpu::VkFormatStencilBits(fFormat);
}
uint32_t channelMask() const override {
return skgpu::VkFormatChannels(fFormat);
}
GrColorFormatDesc desc() const override {
return GrVkFormatDesc(fFormat);
}
bool equal(const GrBackendFormatData* that) const override {
SkASSERT(!that || that->type() == GrBackendApi::kVulkan);
if (auto otherVk = static_cast<const GrVkBackendFormatData*>(that)) {
return fFormat == otherVk->fFormat &&
fYcbcrConversionInfo == otherVk->fYcbcrConversionInfo;
}
return false;
}
std::string toString() const override {
#if defined(SK_DEBUG) || GR_TEST_UTILS
return skgpu::VkFormatToStr(fFormat);
#else
return "";
#endif
}
void copyTo(AnyFormatData& formatData) const override {
formatData.emplace<GrVkBackendFormatData>(fFormat, fYcbcrConversionInfo);
}
void makeTexture2D() override {
// If we have a ycbcr we remove it from the backend format and set the VkFormat to
// R8G8B8A8_UNORM
if (fYcbcrConversionInfo.isValid()) {
fYcbcrConversionInfo = GrVkYcbcrConversionInfo();
fFormat = VK_FORMAT_R8G8B8A8_UNORM;
}
}
#if defined(SK_DEBUG)
GrBackendApi type() const override { return GrBackendApi::kVulkan; }
#endif
VkFormat fFormat;
GrVkYcbcrConversionInfo fYcbcrConversionInfo;
};
static const GrVkBackendFormatData* get_and_cast_data(const GrBackendFormat& format) {
auto data = GrBackendSurfacePriv::GetBackendData(format);
SkASSERT(!data || data->type() == GrBackendApi::kVulkan);
return static_cast<const GrVkBackendFormatData*>(data);
}
namespace GrBackendFormats {
GrBackendFormat MakeVk(VkFormat format, bool willUseDRMFormatModifiers) {
return GrBackendSurfacePriv::MakeGrBackendFormat(
GrTextureType::k2D,
GrBackendApi::kVulkan,
GrVkBackendFormatData(format, GrVkYcbcrConversionInfo{}));
}
GrBackendFormat MakeVk(const GrVkYcbcrConversionInfo& ycbcrInfo, bool willUseDRMFormatModifiers) {
SkASSERT(ycbcrInfo.isValid());
GrTextureType textureType =
((ycbcrInfo.isValid() && ycbcrInfo.fExternalFormat) || willUseDRMFormatModifiers)
? GrTextureType::kExternal
: GrTextureType::k2D;
return GrBackendSurfacePriv::MakeGrBackendFormat(
textureType,
GrBackendApi::kVulkan,
GrVkBackendFormatData(ycbcrInfo.fFormat, ycbcrInfo));
}
bool AsVkFormat(const GrBackendFormat& format, VkFormat* vkFormat) {
SkASSERT(vkFormat);
if (format.isValid() && format.backend() == GrBackendApi::kVulkan) {
const GrVkBackendFormatData* data = get_and_cast_data(format);
SkASSERT(data);
*vkFormat = data->asVkFormat();
return true;
}
return false;
}
const GrVkYcbcrConversionInfo* GetVkYcbcrConversionInfo(const GrBackendFormat& format) {
if (format.isValid() && format.backend() == GrBackendApi::kVulkan) {
const GrVkBackendFormatData* data = get_and_cast_data(format);
SkASSERT(data);
return data->getYcbcrConversionInfo();
}
return nullptr;
}
} // namespace GrBackendFormats
class GrVkBackendTextureData final : public GrBackendTextureData {
public:
GrVkBackendTextureData(const GrVkImageInfo& info,
sk_sp<skgpu::MutableTextureState> mutableState = nullptr)
: fVkInfo(info) {
if (mutableState) {
fMutableState = std::move(mutableState);
} else {
fMutableState =
sk_make_sp<skgpu::MutableTextureState>(skgpu::MutableTextureStates::MakeVulkan(
info.fImageLayout, info.fCurrentQueueFamily));
}
}
const GrVkImageInfo& info() const { return fVkInfo; }
sk_sp<skgpu::MutableTextureState> getMutableState() const override {
return fMutableState;
}
void setMutableState(const skgpu::MutableTextureState& state) override {
fMutableState->set(state);
}
skgpu::MutableTextureState* mutableState() { return fMutableState.get(); }
const skgpu::MutableTextureState* mutableState() const { return fMutableState.get(); }
private:
void copyTo(AnyTextureData& textureData) const override {
textureData.emplace<GrVkBackendTextureData>(fVkInfo, fMutableState);
}
bool isProtected() const override { return fVkInfo.fProtected == skgpu::Protected::kYes; }
bool equal(const GrBackendTextureData* that) const override {
SkASSERT(!that || that->type() == GrBackendApi::kVulkan);
if (auto otherVk = static_cast<const GrVkBackendTextureData*>(that)) {
// For our tests when checking equality we are assuming both backendTexture objects will
// be using the same mutable state object.
if (fMutableState != otherVk->fMutableState) {
return false;
}
return GrVkImageInfoWithMutableState(fVkInfo, fMutableState.get()) ==
GrVkImageInfoWithMutableState(otherVk->fVkInfo, fMutableState.get());
}
return false;
}
bool isSameTexture(const GrBackendTextureData* that) const override {
SkASSERT(!that || that->type() == GrBackendApi::kVulkan);
if (auto otherVk = static_cast<const GrVkBackendTextureData*>(that)) {
return fVkInfo.fImage == otherVk->fVkInfo.fImage;
}
return false;
}
GrBackendFormat getBackendFormat() const override {
auto info = GrVkImageInfoWithMutableState(fVkInfo, fMutableState.get());
bool usesDRMModifier = info.fImageTiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
if (info.fYcbcrConversionInfo.isValid()) {
SkASSERT(info.fFormat == info.fYcbcrConversionInfo.fFormat);
return GrBackendFormats::MakeVk(info.fYcbcrConversionInfo, usesDRMModifier);
}
return GrBackendFormats::MakeVk(info.fFormat, usesDRMModifier);
}
#if defined(SK_DEBUG)
GrBackendApi type() const override { return GrBackendApi::kVulkan; }
#endif
GrVkImageInfo fVkInfo;
sk_sp<skgpu::MutableTextureState> fMutableState;
};
static const GrVkBackendTextureData* get_and_cast_data(const GrBackendTexture& texture) {
auto data = GrBackendSurfacePriv::GetBackendData(texture);
SkASSERT(!data || data->type() == GrBackendApi::kVulkan);
return static_cast<const GrVkBackendTextureData*>(data);
}
static GrVkBackendTextureData* get_and_cast_data(GrBackendTexture* texture) {
auto data = GrBackendSurfacePriv::GetBackendData(texture);
SkASSERT(!data || data->type() == GrBackendApi::kVulkan);
return static_cast<GrVkBackendTextureData*>(data);
}
static GrTextureType vk_image_info_to_texture_type(const GrVkImageInfo& info) {
if ((info.fYcbcrConversionInfo.isValid() && info.fYcbcrConversionInfo.fExternalFormat != 0) ||
info.fImageTiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
return GrTextureType::kExternal;
}
return GrTextureType::k2D;
}
static const VkImageUsageFlags kDefaultUsageFlags =
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
static const VkImageUsageFlags kDefaultRTUsageFlags =
kDefaultUsageFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
// We don't know if the backend texture is made renderable or not, so we default the usage flags
// to include color attachment as well.
static const VkImageUsageFlags kDefaultTexRTUsageFlags =
kDefaultUsageFlags | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
static GrVkImageInfo apply_default_usage_flags(const GrVkImageInfo& info,
VkImageUsageFlags defaultFlags) {
if (info.fImageUsageFlags == 0) {
GrVkImageInfo newInfo = info;
newInfo.fImageUsageFlags = defaultFlags;
return newInfo;
}
return info;
}
namespace GrBackendTextures {
GrBackendTexture MakeVk(int width,
int height,
const GrVkImageInfo& vkInfo,
std::string_view label) {
return GrBackendSurfacePriv::MakeGrBackendTexture(
width,
height,
label,
skgpu::Mipmapped(vkInfo.fLevelCount > 1),
GrBackendApi::kVulkan,
vk_image_info_to_texture_type(vkInfo),
GrVkBackendTextureData(apply_default_usage_flags(vkInfo, kDefaultTexRTUsageFlags)));
}
GrBackendTexture MakeVk(int width,
int height,
const GrVkImageInfo& vkInfo,
sk_sp<skgpu::MutableTextureState> mutableState) {
return GrBackendSurfacePriv::MakeGrBackendTexture(
width,
height,
/*label=*/{},
skgpu::Mipmapped(vkInfo.fLevelCount > 1),
GrBackendApi::kVulkan,
vk_image_info_to_texture_type(vkInfo),
GrVkBackendTextureData(apply_default_usage_flags(vkInfo, kDefaultTexRTUsageFlags),
std::move(mutableState)));
}
bool GetVkImageInfo(const GrBackendTexture& tex, GrVkImageInfo* outInfo) {
if (!tex.isValid() || tex.backend() != GrBackendApi::kVulkan) {
return false;
}
const GrVkBackendTextureData* data = get_and_cast_data(tex);
SkASSERT(data);
*outInfo = GrVkImageInfoWithMutableState(data->info(), data->mutableState());
return true;
}
void SetVkImageLayout(GrBackendTexture* tex, VkImageLayout layout) {
if (tex && tex->isValid() && tex->backend() == GrBackendApi::kVulkan) {
GrVkBackendTextureData* data = get_and_cast_data(tex);
SkASSERT(data);
skgpu::MutableTextureStates::SetVkImageLayout(data->mutableState(), layout);
}
}
} // namespace GrBackendTextures
class GrVkBackendRenderTargetData final : public GrBackendRenderTargetData {
public:
GrVkBackendRenderTargetData(const GrVkImageInfo& info,
sk_sp<skgpu::MutableTextureState> mutableState = nullptr)
: fVkInfo(info) {
if (mutableState) {
fMutableState = std::move(mutableState);
} else {
fMutableState =
sk_make_sp<skgpu::MutableTextureState>(skgpu::MutableTextureStates::MakeVulkan(
info.fImageLayout, info.fCurrentQueueFamily));
}
}
const GrVkImageInfo& info() const { return fVkInfo; }
sk_sp<skgpu::MutableTextureState> getMutableState() const override {
return fMutableState;
}
void setMutableState(const skgpu::MutableTextureState& state) override {
fMutableState->set(state);
}
skgpu::MutableTextureState* mutableState() { return fMutableState.get(); }
const skgpu::MutableTextureState* mutableState() const { return fMutableState.get(); }
private:
GrBackendFormat getBackendFormat() const override {
auto info = GrVkImageInfoWithMutableState(fVkInfo, fMutableState.get());
if (info.fYcbcrConversionInfo.isValid()) {
SkASSERT(info.fFormat == info.fYcbcrConversionInfo.fFormat);
return GrBackendFormats::MakeVk(info.fYcbcrConversionInfo);
}
return GrBackendFormats::MakeVk(info.fFormat);
}
bool isProtected() const override { return fVkInfo.fProtected == skgpu::Protected::kYes; }
bool equal(const GrBackendRenderTargetData* that) const override {
SkASSERT(!that || that->type() == GrBackendApi::kVulkan);
if (auto otherVk = static_cast<const GrVkBackendRenderTargetData*>(that)) {
// For our tests when checking equality we are assuming both objects will be using the
// same mutable state object.
if (fMutableState != otherVk->fMutableState) {
return false;
}
return GrVkImageInfoWithMutableState(fVkInfo, fMutableState.get()) ==
GrVkImageInfoWithMutableState(otherVk->fVkInfo, fMutableState.get());
}
return false;
}
void copyTo(AnyRenderTargetData& rtData) const override {
rtData.emplace<GrVkBackendRenderTargetData>(fVkInfo, fMutableState);
}
#if defined(SK_DEBUG)
GrBackendApi type() const override { return GrBackendApi::kVulkan; }
#endif
GrVkImageInfo fVkInfo;
sk_sp<skgpu::MutableTextureState> fMutableState;
};
static const GrVkBackendRenderTargetData* get_and_cast_data(const GrBackendRenderTarget& rt) {
auto data = GrBackendSurfacePriv::GetBackendData(rt);
SkASSERT(!data || data->type() == GrBackendApi::kVulkan);
return static_cast<const GrVkBackendRenderTargetData*>(data);
}
static GrVkBackendRenderTargetData* get_and_cast_data(GrBackendRenderTarget* rt) {
auto data = GrBackendSurfacePriv::GetBackendData(rt);
SkASSERT(!data || data->type() == GrBackendApi::kVulkan);
return static_cast<GrVkBackendRenderTargetData*>(data);
}
namespace GrBackendRenderTargets {
GrBackendRenderTarget MakeVk(int width, int height, const GrVkImageInfo& vkInfo) {
return GrBackendSurfacePriv::MakeGrBackendRenderTarget(
width,
height,
std::max(1U, vkInfo.fSampleCount),
/*stencilBits=*/0,
GrBackendApi::kVulkan,
/*framebufferOnly=*/false,
GrVkBackendRenderTargetData(apply_default_usage_flags(vkInfo, kDefaultRTUsageFlags)));
}
GrBackendRenderTarget MakeVk(int width,
int height,
const GrVkImageInfo& vkInfo,
sk_sp<skgpu::MutableTextureState> mutableState) {
return GrBackendSurfacePriv::MakeGrBackendRenderTarget(
width,
height,
std::max(1U, vkInfo.fSampleCount),
/*stencilBits=*/0,
GrBackendApi::kVulkan,
/*framebufferOnly=*/false,
GrVkBackendRenderTargetData(apply_default_usage_flags(vkInfo, kDefaultRTUsageFlags),
std::move(mutableState)));
}
bool GetVkImageInfo(const GrBackendRenderTarget& rt, GrVkImageInfo* outInfo) {
if (!rt.isValid() || rt.backend() != GrBackendApi::kVulkan) {
return false;
}
const GrVkBackendRenderTargetData* data = get_and_cast_data(rt);
SkASSERT(data);
*outInfo = GrVkImageInfoWithMutableState(data->info(), data->mutableState());
return true;
}
void SetVkImageLayout(GrBackendRenderTarget* rt, VkImageLayout layout) {
if (rt && rt->isValid() && rt->backend() == GrBackendApi::kVulkan) {
GrVkBackendRenderTargetData* data = get_and_cast_data(rt);
skgpu::MutableTextureStates::SetVkImageLayout(data->mutableState(), layout);
}
}
} // namespace GrBackendRenderTargets