| /* |
| * 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/gl/GrGLBackendSurface.h" |
| |
| #include "include/core/SkRefCnt.h" |
| #include "include/core/SkTextureCompressionType.h" |
| #include "include/gpu/GrBackendSurface.h" |
| #include "include/gpu/GrTypes.h" |
| #include "include/gpu/gl/GrGLTypes.h" |
| #include "include/private/base/SkAssert.h" |
| #include "include/private/base/SkDebug.h" |
| #include "include/private/gpu/ganesh/GrTypesPriv.h" |
| #include "src/gpu/ganesh/GrBackendSurfacePriv.h" |
| #include "src/gpu/ganesh/gl/GrGLBackendSurfacePriv.h" |
| #include "src/gpu/ganesh/gl/GrGLDefines.h" |
| #include "src/gpu/ganesh/gl/GrGLTypesPriv.h" |
| #include "src/gpu/ganesh/gl/GrGLUtil.h" |
| |
| #include <algorithm> |
| #include <cstddef> |
| #include <cstdint> |
| #include <string> |
| |
| class GrGLBackendFormatData final : public GrBackendFormatData { |
| public: |
| GrGLBackendFormatData(GrGLenum format) : fGLFormat(format) {} |
| |
| GrGLenum asEnum() const { return fGLFormat; } |
| |
| private: |
| SkTextureCompressionType compressionType() const override { |
| switch (GrGLFormatFromGLEnum(fGLFormat)) { |
| case GrGLFormat::kCOMPRESSED_ETC1_RGB8: |
| case GrGLFormat::kCOMPRESSED_RGB8_ETC2: |
| return SkTextureCompressionType::kETC2_RGB8_UNORM; |
| case GrGLFormat::kCOMPRESSED_RGB8_BC1: |
| return SkTextureCompressionType::kBC1_RGB8_UNORM; |
| case GrGLFormat::kCOMPRESSED_RGBA8_BC1: |
| return SkTextureCompressionType::kBC1_RGBA8_UNORM; |
| default: |
| return SkTextureCompressionType::kNone; |
| } |
| } |
| |
| size_t bytesPerBlock() const override { |
| return GrGLFormatBytesPerBlock(GrGLFormatFromGLEnum(fGLFormat)); |
| } |
| |
| int stencilBits() const override { |
| return GrGLFormatStencilBits(GrGLFormatFromGLEnum(fGLFormat)); |
| } |
| |
| uint32_t channelMask() const override { |
| return GrGLFormatChannels(GrGLFormatFromGLEnum(fGLFormat)); |
| } |
| |
| GrColorFormatDesc desc() const override { |
| return GrGLFormatDesc(GrGLFormatFromGLEnum(fGLFormat)); |
| } |
| |
| bool equal(const GrBackendFormatData* that) const override { |
| SkASSERT(!that || that->type() == GrBackendApi::kOpenGL); |
| if (auto otherGL = static_cast<const GrGLBackendFormatData*>(that)) { |
| return fGLFormat == otherGL->fGLFormat; |
| } |
| return false; |
| } |
| |
| std::string toString() const override { |
| #if defined(SK_DEBUG) || defined(GR_TEST_UTILS) |
| return GrGLFormatToStr(fGLFormat); |
| #else |
| return ""; |
| #endif |
| } |
| |
| void copyTo(AnyFormatData& formatData) const override { |
| formatData.emplace<GrGLBackendFormatData>(fGLFormat); |
| } |
| |
| #if defined(SK_DEBUG) |
| GrBackendApi type() const override { return GrBackendApi::kOpenGL; } |
| #endif |
| |
| GrGLenum fGLFormat; // the sized, internal format of the GL resource |
| }; |
| |
| static GrTextureType gl_target_to_gr_target(GrGLenum target) { |
| switch (target) { |
| case GR_GL_TEXTURE_NONE: |
| return GrTextureType::kNone; |
| case GR_GL_TEXTURE_2D: |
| return GrTextureType::k2D; |
| case GR_GL_TEXTURE_RECTANGLE: |
| return GrTextureType::kRectangle; |
| case GR_GL_TEXTURE_EXTERNAL: |
| return GrTextureType::kExternal; |
| default: |
| SkUNREACHABLE; |
| } |
| } |
| |
| static const GrGLBackendFormatData* get_and_cast_data(const GrBackendFormat& format) { |
| auto data = GrBackendSurfacePriv::GetBackendData(format); |
| SkASSERT(!data || data->type() == GrBackendApi::kOpenGL); |
| return static_cast<const GrGLBackendFormatData*>(data); |
| } |
| |
| namespace GrBackendFormats { |
| GrBackendFormat MakeGL(GrGLenum format, GrGLenum target) { |
| return GrBackendSurfacePriv::MakeGrBackendFormat( |
| gl_target_to_gr_target(target), GrBackendApi::kOpenGL, GrGLBackendFormatData(format)); |
| } |
| |
| GrGLFormat AsGLFormat(const GrBackendFormat& format) { |
| if (format.isValid() && format.backend() == GrBackendApi::kOpenGL) { |
| const GrGLBackendFormatData* data = get_and_cast_data(format); |
| SkASSERT(data); |
| return GrGLFormatFromGLEnum(data->asEnum()); |
| } |
| return GrGLFormat::kUnknown; |
| } |
| |
| GrGLenum AsGLFormatEnum(const GrBackendFormat& format) { |
| if (format.isValid() && format.backend() == GrBackendApi::kOpenGL) { |
| const GrGLBackendFormatData* data = get_and_cast_data(format); |
| SkASSERT(data); |
| return data->asEnum(); |
| } |
| return 0; |
| } |
| } // namespace GrBackendFormats |
| |
| GrGLBackendTextureData::GrGLBackendTextureData(const GrGLTextureInfo& info, |
| sk_sp<GrGLTextureParameters> params) |
| : fGLInfo(info, params) {} |
| |
| void GrGLBackendTextureData::copyTo(AnyTextureData& textureData) const { |
| textureData.emplace<GrGLBackendTextureData>(fGLInfo.info(), fGLInfo.refParameters()); |
| } |
| |
| bool GrGLBackendTextureData::isProtected() const { return fGLInfo.isProtected(); } |
| |
| bool GrGLBackendTextureData::equal(const GrBackendTextureData* that) const { |
| SkASSERT(!that || that->type() == GrBackendApi::kOpenGL); |
| if (auto otherGL = static_cast<const GrGLBackendTextureData*>(that)) { |
| return fGLInfo.info() == otherGL->fGLInfo.info(); |
| } |
| return false; |
| } |
| |
| bool GrGLBackendTextureData::isSameTexture(const GrBackendTextureData* that) const { |
| SkASSERT(!that || that->type() == GrBackendApi::kOpenGL); |
| if (auto otherGL = static_cast<const GrGLBackendTextureData*>(that)) { |
| return fGLInfo.info().fID == otherGL->fGLInfo.info().fID; |
| } |
| return false; |
| } |
| |
| GrBackendFormat GrGLBackendTextureData::getBackendFormat() const { |
| return GrBackendFormats::MakeGL(fGLInfo.info().fFormat, fGLInfo.info().fTarget); |
| } |
| |
| static const GrGLBackendTextureData* get_and_cast_data(const GrBackendTexture& texture) { |
| auto data = GrBackendSurfacePriv::GetBackendData(texture); |
| SkASSERT(!data || data->type() == GrBackendApi::kOpenGL); |
| return static_cast<const GrGLBackendTextureData*>(data); |
| } |
| |
| static GrGLBackendTextureData* get_and_cast_data(GrBackendTexture* texture) { |
| auto data = GrBackendSurfacePriv::GetBackendData(texture); |
| SkASSERT(!data || data->type() == GrBackendApi::kOpenGL); |
| return static_cast<GrGLBackendTextureData*>(data); |
| } |
| |
| namespace GrBackendTextures { |
| GrBackendTexture MakeGL(int width, |
| int height, |
| skgpu::Mipmapped mipped, |
| const GrGLTextureInfo& glInfo, |
| std::string_view label) { |
| auto tex = GrBackendSurfacePriv::MakeGrBackendTexture( |
| width, |
| height, |
| label, |
| mipped, |
| GrBackendApi::kOpenGL, |
| gl_target_to_gr_target(glInfo.fTarget), |
| GrGLBackendTextureData(glInfo, sk_make_sp<GrGLTextureParameters>())); |
| // Make no assumptions about client's texture's parameters. |
| GLTextureParametersModified(&tex); |
| return tex; |
| } |
| |
| GrBackendTexture MakeGL(int width, |
| int height, |
| skgpu::Mipmapped mipped, |
| const GrGLTextureInfo& glInfo, |
| sk_sp<GrGLTextureParameters> params, |
| std::string_view label) { |
| return GrBackendSurfacePriv::MakeGrBackendTexture(width, |
| height, |
| label, |
| mipped, |
| GrBackendApi::kOpenGL, |
| gl_target_to_gr_target(glInfo.fTarget), |
| GrGLBackendTextureData(glInfo, params)); |
| } |
| |
| bool GetGLTextureInfo(const GrBackendTexture& tex, GrGLTextureInfo* outInfo) { |
| if (!tex.isValid() || tex.backend() != GrBackendApi::kOpenGL) { |
| return false; |
| } |
| const GrGLBackendTextureData* data = get_and_cast_data(tex); |
| SkASSERT(data); |
| *outInfo = data->info().info(); |
| return true; |
| } |
| |
| void GLTextureParametersModified(GrBackendTexture* tex) { |
| if (tex && tex->isValid() && tex->backend() == GrBackendApi::kOpenGL) { |
| GrGLBackendTextureData* data = get_and_cast_data(tex); |
| SkASSERT(data); |
| data->info().parameters()->invalidate(); |
| } |
| } |
| } // namespace GrBackendTextures |
| |
| class GrGLBackendRenderTargetData final : public GrBackendRenderTargetData { |
| public: |
| GrGLBackendRenderTargetData(GrGLFramebufferInfo info) : fGLInfo(info) {} |
| |
| GrGLFramebufferInfo info() const { return fGLInfo; } |
| |
| private: |
| GrBackendFormat getBackendFormat() const override { |
| return GrBackendFormats::MakeGL(fGLInfo.fFormat, GR_GL_TEXTURE_NONE); |
| } |
| |
| bool isProtected() const override { return fGLInfo.isProtected(); } |
| |
| bool equal(const GrBackendRenderTargetData* that) const override { |
| SkASSERT(!that || that->type() == GrBackendApi::kOpenGL); |
| if (auto otherGL = static_cast<const GrGLBackendRenderTargetData*>(that)) { |
| return fGLInfo == otherGL->fGLInfo; |
| } |
| return false; |
| } |
| |
| void copyTo(AnyRenderTargetData& rtData) const override { |
| rtData.emplace<GrGLBackendRenderTargetData>(fGLInfo); |
| } |
| |
| #if defined(SK_DEBUG) |
| GrBackendApi type() const override { return GrBackendApi::kOpenGL; } |
| #endif |
| |
| GrGLFramebufferInfo fGLInfo; |
| }; |
| |
| static const GrGLBackendRenderTargetData* get_and_cast_data(const GrBackendRenderTarget& rt) { |
| auto data = GrBackendSurfacePriv::GetBackendData(rt); |
| SkASSERT(!data || data->type() == GrBackendApi::kOpenGL); |
| return static_cast<const GrGLBackendRenderTargetData*>(data); |
| } |
| |
| namespace GrBackendRenderTargets { |
| // The GrGLTextureInfo must have a valid fFormat. If wrapping in an SkSurface we require the |
| // stencil bits to be either 0, 8 or 16. |
| GrBackendRenderTarget MakeGL( |
| int width, int height, int sampleCnt, int stencilBits, const GrGLFramebufferInfo& glInfo) { |
| return GrBackendSurfacePriv::MakeGrBackendRenderTarget(width, |
| height, |
| std::max(1, sampleCnt), |
| stencilBits, |
| GrBackendApi::kOpenGL, |
| /*framebufferOnly=*/false, |
| GrGLBackendRenderTargetData(glInfo)); |
| } |
| |
| bool GetGLFramebufferInfo(const GrBackendRenderTarget& rt, GrGLFramebufferInfo* outInfo) { |
| if (!rt.isValid() || rt.backend() != GrBackendApi::kOpenGL) { |
| return false; |
| } |
| const GrGLBackendRenderTargetData* data = get_and_cast_data(rt); |
| SkASSERT(data); |
| *outInfo = data->info(); |
| return true; |
| } |
| |
| } // namespace GrBackendRenderTargets |