| /* | |
| * Copyright 2026 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/mock/GrMockBackendSurface.h" | |
| #include "include/core/SkTextureCompressionType.h" | |
| #include "include/gpu/ganesh/GrTypes.h" | |
| #include "include/private/SkAssert.h" | |
| #include "include/private/gpu/ganesh/GrTypesPriv.h" | |
| #include "src/core/SkCompressedDataUtils.h" | |
| #include "src/gpu/GpuTypesPriv.h" | |
| #include "src/gpu/ganesh/GrBackendSurfacePriv.h" | |
| #include "src/gpu/ganesh/GrUtil.h" | |
| #include <algorithm> | |
| class GrMockBackendFormatData final : public GrBackendFormatData { | |
| public: | |
| GrMockBackendFormatData(GrColorType colorType, | |
| SkTextureCompressionType compression, | |
| bool isStencilFormat) | |
| : fColorType(colorType) | |
| , fCompressionType(compression) | |
| , fIsStencilFormat(isStencilFormat) { | |
| SkASSERT(this->validate()); | |
| } | |
| GrColorType colorType() const { return fColorType; } | |
| SkTextureCompressionType compressionType() const override { return fCompressionType; } | |
| bool isStencilFormat() const { return fIsStencilFormat; } | |
| private: | |
| size_t bytesPerBlock() const override { | |
| if (fCompressionType != SkTextureCompressionType::kNone) { | |
| return SkCompressedDataSize(fCompressionType, {1, 1}, nullptr, false); | |
| } | |
| if (fIsStencilFormat) { | |
| return 4; | |
| } | |
| return GrColorTypeBytesPerPixel(fColorType); | |
| } | |
| int stencilBits() const override { return fIsStencilFormat ? 8 : 0; } | |
| uint32_t channelMask() const override { return GrColorTypeChannelFlags(fColorType); } | |
| GrColorFormatDesc desc() const override { return GrGetColorTypeDesc(fColorType); } | |
| bool equal(const GrBackendFormatData* that) const override { | |
| SkASSERT(!that || that->type() == GrBackendApi::kMock); | |
| if (auto otherMock = static_cast<const GrMockBackendFormatData*>(that)) { | |
| return fColorType == otherMock->fColorType && | |
| fCompressionType == otherMock->fCompressionType && | |
| fIsStencilFormat == otherMock->fIsStencilFormat; | |
| } | |
| return false; | |
| } | |
| std::string toString() const override { | |
| #if defined(SK_DEBUG) || defined(GPU_TEST_UTILS) | |
| std::string str = GrColorTypeToStr(fColorType); | |
| str += "-"; | |
| str += skgpu::CompressionTypeToStr(fCompressionType); | |
| if (fIsStencilFormat) { | |
| str += "-stencil"; | |
| } | |
| return str; | |
| #else | |
| return ""; | |
| #endif | |
| } | |
| void copyTo(AnyFormatData& formatData) const override { | |
| formatData.emplace<GrMockBackendFormatData>(fColorType, fCompressionType, fIsStencilFormat); | |
| } | |
| #if defined(SK_DEBUG) | |
| GrBackendApi type() const override { return GrBackendApi::kMock; } | |
| #endif | |
| bool validate() const { | |
| int trueStates = 0; | |
| if (fCompressionType != SkTextureCompressionType::kNone) { | |
| trueStates++; | |
| } | |
| if (fColorType != GrColorType::kUnknown) { | |
| trueStates++; | |
| } | |
| if (fIsStencilFormat) { | |
| trueStates++; | |
| } | |
| return trueStates == 1; | |
| } | |
| GrColorType fColorType; | |
| SkTextureCompressionType fCompressionType; | |
| bool fIsStencilFormat; | |
| }; | |
| static const GrMockBackendFormatData* get_and_cast_data(const GrBackendFormat& format) { | |
| auto data = GrBackendSurfacePriv::GetBackendData(format); | |
| SkASSERT(!data || data->type() == GrBackendApi::kMock); | |
| return static_cast<const GrMockBackendFormatData*>(data); | |
| } | |
| namespace GrBackendFormats { | |
| GrBackendFormat MakeMockColorType(GrColorType colorType) { | |
| return GrBackendSurfacePriv::MakeGrBackendFormat( | |
| GrTextureType::k2D, | |
| GrBackendApi::kMock, | |
| GrMockBackendFormatData(colorType, SkTextureCompressionType::kNone, false)); | |
| } | |
| GrBackendFormat MakeMockCompressionType(SkTextureCompressionType compression) { | |
| return GrBackendSurfacePriv::MakeGrBackendFormat( | |
| GrTextureType::k2D, | |
| GrBackendApi::kMock, | |
| GrMockBackendFormatData(GrColorType::kUnknown, compression, false)); | |
| } | |
| GrBackendFormat MakeMockStencilFormat() { | |
| return GrBackendSurfacePriv::MakeGrBackendFormat( | |
| GrTextureType::k2D, | |
| GrBackendApi::kMock, | |
| GrMockBackendFormatData(GrColorType::kUnknown, SkTextureCompressionType::kNone, true)); | |
| } | |
| GrColorType AsMockColorType(const GrBackendFormat& format) { | |
| if (format.isValid() && format.backend() == GrBackendApi::kMock) { | |
| return get_and_cast_data(format)->colorType(); | |
| } | |
| return GrColorType::kUnknown; | |
| } | |
| SkTextureCompressionType AsMockCompressionType(const GrBackendFormat& format) { | |
| if (format.isValid() && format.backend() == GrBackendApi::kMock) { | |
| return get_and_cast_data(format)->compressionType(); | |
| } | |
| return SkTextureCompressionType::kNone; | |
| } | |
| bool IsMockStencilFormat(const GrBackendFormat& format) { | |
| if (format.isValid() && format.backend() == GrBackendApi::kMock) { | |
| return get_and_cast_data(format)->isStencilFormat(); | |
| } | |
| return false; | |
| } | |
| } // namespace GrBackendFormats | |
| class GrMockBackendTextureData final : public GrBackendTextureData { | |
| public: | |
| GrMockBackendTextureData(const GrMockTextureInfo& info) : fInfo(info) {} | |
| const GrMockTextureInfo& info() const { return fInfo; } | |
| private: | |
| void copyTo(AnyTextureData& textureData) const override { | |
| textureData.emplace<GrMockBackendTextureData>(fInfo); | |
| } | |
| bool isProtected() const override { return fInfo.isProtected(); } | |
| #if defined(GPU_TEST_UTILS) | |
| bool equal(const GrBackendTextureData* that) const override { | |
| SkASSERT(!that || that->type() == GrBackendApi::kMock); | |
| if (auto otherMock = static_cast<const GrMockBackendTextureData*>(that)) { | |
| return fInfo == otherMock->fInfo; | |
| } | |
| return false; | |
| } | |
| #endif | |
| bool isSameTexture(const GrBackendTextureData* that) const override { | |
| SkASSERT(!that || that->type() == GrBackendApi::kMock); | |
| if (auto otherMock = static_cast<const GrMockBackendTextureData*>(that)) { | |
| return fInfo.id() == otherMock->fInfo.id(); | |
| } | |
| return false; | |
| } | |
| GrBackendFormat getBackendFormat() const override { return fInfo.getBackendFormat(); } | |
| #if defined(SK_DEBUG) | |
| GrBackendApi type() const override { return GrBackendApi::kMock; } | |
| #endif | |
| GrMockTextureInfo fInfo; | |
| }; | |
| static const GrMockBackendTextureData* get_and_cast_data(const GrBackendTexture& texture) { | |
| auto data = GrBackendSurfacePriv::GetBackendData(texture); | |
| SkASSERT(!data || data->type() == GrBackendApi::kMock); | |
| return static_cast<const GrMockBackendTextureData*>(data); | |
| } | |
| namespace GrBackendTextures { | |
| GrBackendTexture MakeMock(int width, | |
| int height, | |
| skgpu::Mipmapped mipmapped, | |
| const GrMockTextureInfo& mockInfo, | |
| std::string_view label) { | |
| return GrBackendSurfacePriv::MakeGrBackendTexture(width, | |
| height, | |
| label, | |
| mipmapped, | |
| GrBackendApi::kMock, | |
| GrTextureType::k2D, | |
| GrMockBackendTextureData(mockInfo)); | |
| } | |
| GrMockTextureInfo GetMockTextureInfo(const GrBackendTexture& tex) { | |
| if (!tex.isValid() || tex.backend() != GrBackendApi::kMock) { | |
| SkDEBUGFAIL("Mismatching backend or uninitialized GrBackendTexture\n"); | |
| return {}; | |
| } | |
| return get_and_cast_data(tex)->info(); | |
| } | |
| } // namespace GrBackendTextures | |
| class GrMockBackendRenderTargetData final : public GrBackendRenderTargetData { | |
| public: | |
| GrMockBackendRenderTargetData(const GrMockRenderTargetInfo& info) : fInfo(info) {} | |
| const GrMockRenderTargetInfo& info() const { return fInfo; } | |
| private: | |
| void copyTo(AnyRenderTargetData& rtData) const override { | |
| rtData.emplace<GrMockBackendRenderTargetData>(fInfo); | |
| } | |
| bool isProtected() const override { return fInfo.isProtected(); } | |
| #if defined(GPU_TEST_UTILS) | |
| bool equal(const GrBackendRenderTargetData* that) const override { | |
| SkASSERT(!that || that->type() == GrBackendApi::kMock); | |
| if (auto otherMock = static_cast<const GrMockBackendRenderTargetData*>(that)) { | |
| return fInfo == otherMock->fInfo; | |
| } | |
| return false; | |
| } | |
| #endif | |
| GrBackendFormat getBackendFormat() const override { return fInfo.getBackendFormat(); } | |
| #if defined(SK_DEBUG) | |
| GrBackendApi type() const override { return GrBackendApi::kMock; } | |
| #endif | |
| GrMockRenderTargetInfo fInfo; | |
| }; | |
| static const GrMockBackendRenderTargetData* get_and_cast_data(const GrBackendRenderTarget& rt) { | |
| auto data = GrBackendSurfacePriv::GetBackendData(rt); | |
| SkASSERT(!data || data->type() == GrBackendApi::kMock); | |
| return static_cast<const GrMockBackendRenderTargetData*>(data); | |
| } | |
| namespace GrBackendRenderTargets { | |
| GrBackendRenderTarget MakeMock(int width, | |
| int height, | |
| int sampleCnt, | |
| int stencilBits, | |
| const GrMockRenderTargetInfo& mockInfo) { | |
| return GrBackendSurfacePriv::MakeGrBackendRenderTarget(width, | |
| height, | |
| std::max(1, sampleCnt), | |
| stencilBits, | |
| GrBackendApi::kMock, | |
| false, /*framebufferOnly*/ | |
| GrMockBackendRenderTargetData(mockInfo)); | |
| } | |
| GrMockRenderTargetInfo GetMockRenderTargetInfo(const GrBackendRenderTarget& rt) { | |
| if (!rt.isValid() || rt.backend() != GrBackendApi::kMock) { | |
| SkDEBUGFAIL("Mismatching backend or uninitialized GrBackendRenderTarget\n"); | |
| return {}; | |
| } | |
| return get_and_cast_data(rt)->info(); | |
| } | |
| } // namespace GrBackendRenderTargets |