| /* |
| * 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/base/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 |