| /* |
| * Copyright 2017 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/gpu/GrBackendSurface.h" |
| |
| #include "include/core/SkTextureCompressionType.h" |
| #include "include/gpu/GrTypes.h" |
| #include "include/gpu/MutableTextureState.h" // IWYU pragma: keep |
| #include "include/private/base/SkAssert.h" |
| #include "include/private/gpu/ganesh/GrTypesPriv.h" |
| #include "src/gpu/GpuTypesPriv.h" |
| #include "src/gpu/ganesh/GrBackendSurfacePriv.h" |
| |
| #ifdef SK_DIRECT3D |
| #include "include/gpu/d3d/GrD3DTypes.h" |
| #include "src/gpu/ganesh/d3d/GrD3DResourceState.h" |
| #include "src/gpu/ganesh/d3d/GrD3DUtil.h" |
| #endif |
| |
| #include <algorithm> |
| #include <new> |
| |
| GrBackendFormat::GrBackendFormat() : fValid(false) {} |
| GrBackendFormat::~GrBackendFormat() = default; |
| |
| GrBackendFormat::GrBackendFormat(const GrBackendFormat& that) |
| : fBackend(that.fBackend) |
| , fValid(that.fValid) |
| , fTextureType(that.fTextureType) { |
| if (!fValid) { |
| return; |
| } |
| |
| switch (fBackend) { |
| case GrBackendApi::kOpenGL: |
| case GrBackendApi::kVulkan: |
| case GrBackendApi::kMetal: |
| fFormatData.reset(); |
| that.fFormatData->copyTo(fFormatData); |
| break; // fFormatData is sufficient |
| #ifdef SK_DIRECT3D |
| case GrBackendApi::kDirect3D: |
| fDxgiFormat = that.fDxgiFormat; |
| break; |
| #endif |
| case GrBackendApi::kMock: |
| fMock = that.fMock; |
| break; |
| default: |
| SK_ABORT("Unknown GrBackend"); |
| } |
| } |
| |
| GrBackendFormat& GrBackendFormat::operator=(const GrBackendFormat& that) { |
| if (this != &that) { |
| this->~GrBackendFormat(); |
| new (this) GrBackendFormat(that); |
| } |
| return *this; |
| } |
| |
| #ifdef SK_DIRECT3D |
| GrBackendFormat::GrBackendFormat(DXGI_FORMAT dxgiFormat) |
| : fBackend(GrBackendApi::kDirect3D) |
| , fValid(true) |
| , fDxgiFormat(dxgiFormat) |
| , fTextureType(GrTextureType::k2D) { |
| } |
| |
| bool GrBackendFormat::asDxgiFormat(DXGI_FORMAT* dxgiFormat) const { |
| if (this->isValid() && GrBackendApi::kDirect3D == fBackend) { |
| *dxgiFormat = fDxgiFormat; |
| return true; |
| } |
| return false; |
| } |
| #endif |
| |
| GrBackendFormat::GrBackendFormat(GrColorType colorType, SkTextureCompressionType compression, |
| bool isStencilFormat) |
| : fBackend(GrBackendApi::kMock) |
| , fValid(true) |
| , fTextureType(GrTextureType::k2D) { |
| fMock.fColorType = colorType; |
| fMock.fCompressionType = compression; |
| fMock.fIsStencilFormat = isStencilFormat; |
| SkASSERT(this->validateMock()); |
| } |
| |
| uint32_t GrBackendFormat::channelMask() const { |
| if (!this->isValid()) { |
| return 0; |
| } |
| switch (fBackend) { |
| case GrBackendApi::kOpenGL: |
| case GrBackendApi::kVulkan: |
| case GrBackendApi::kMetal: |
| return fFormatData->channelMask(); |
| #ifdef SK_DIRECT3D |
| case GrBackendApi::kDirect3D: |
| return GrDxgiFormatChannels(fDxgiFormat); |
| #endif |
| case GrBackendApi::kMock: |
| return GrColorTypeChannelFlags(fMock.fColorType); |
| |
| default: |
| return 0; |
| } |
| } |
| |
| GrColorFormatDesc GrBackendFormat::desc() const { |
| if (!this->isValid()) { |
| return GrColorFormatDesc::MakeInvalid(); |
| } |
| switch (fBackend) { |
| case GrBackendApi::kOpenGL: |
| case GrBackendApi::kVulkan: |
| case GrBackendApi::kMetal: |
| return fFormatData->desc(); |
| #ifdef SK_DIRECT3D |
| case GrBackendApi::kDirect3D: |
| return GrDxgiFormatDesc(fDxgiFormat); |
| #endif |
| case GrBackendApi::kMock: |
| return GrGetColorTypeDesc(fMock.fColorType); |
| |
| default: |
| return GrColorFormatDesc::MakeInvalid(); |
| } |
| } |
| |
| #ifdef SK_DEBUG |
| bool GrBackendFormat::validateMock() const { |
| int trueStates = 0; |
| if (fMock.fCompressionType != SkTextureCompressionType::kNone) { |
| trueStates++; |
| } |
| if (fMock.fColorType != GrColorType::kUnknown) { |
| trueStates++; |
| } |
| if (fMock.fIsStencilFormat) { |
| trueStates++; |
| } |
| return trueStates == 1; |
| } |
| #endif |
| |
| GrColorType GrBackendFormat::asMockColorType() const { |
| if (this->isValid() && GrBackendApi::kMock == fBackend) { |
| SkASSERT(this->validateMock()); |
| return fMock.fColorType; |
| } |
| |
| return GrColorType::kUnknown; |
| } |
| |
| SkTextureCompressionType GrBackendFormat::asMockCompressionType() const { |
| if (this->isValid() && GrBackendApi::kMock == fBackend) { |
| SkASSERT(this->validateMock()); |
| return fMock.fCompressionType; |
| } |
| |
| return SkTextureCompressionType::kNone; |
| } |
| |
| bool GrBackendFormat::isMockStencilFormat() const { |
| if (this->isValid() && GrBackendApi::kMock == fBackend) { |
| SkASSERT(this->validateMock()); |
| return fMock.fIsStencilFormat; |
| } |
| |
| return false; |
| } |
| |
| GrBackendFormat GrBackendFormat::makeTexture2D() const { |
| GrBackendFormat copy = *this; |
| // TODO(b/293490566): Remove this kVulkan check once all backends are using fFormatData. |
| if (fBackend==GrBackendApi::kVulkan) { |
| copy.fFormatData->makeTexture2D(); |
| } |
| copy.fTextureType = GrTextureType::k2D; |
| return copy; |
| } |
| |
| GrBackendFormat GrBackendFormat::MakeMock(GrColorType colorType, |
| SkTextureCompressionType compression, |
| bool isStencilFormat) { |
| return GrBackendFormat(colorType, compression, isStencilFormat); |
| } |
| |
| bool GrBackendFormat::operator==(const GrBackendFormat& that) const { |
| // Invalid GrBackendFormats are never equal to anything. |
| if (!fValid || !that.fValid) { |
| return false; |
| } |
| |
| if (fBackend != that.fBackend) { |
| return false; |
| } |
| |
| switch (fBackend) { |
| case GrBackendApi::kOpenGL: |
| case GrBackendApi::kVulkan: |
| case GrBackendApi::kMetal: |
| return fFormatData->equal(that.fFormatData.get()); |
| case GrBackendApi::kMock: |
| return fMock.fColorType == that.fMock.fColorType && |
| fMock.fCompressionType == that.fMock.fCompressionType; |
| #ifdef SK_DIRECT3D |
| case GrBackendApi::kDirect3D: |
| return fDxgiFormat == that.fDxgiFormat; |
| #endif |
| default: |
| SK_ABORT("Unknown GrBackend"); |
| } |
| return false; |
| } |
| |
| #if defined(SK_DEBUG) || defined(GR_TEST_UTILS) |
| #include "include/core/SkString.h" |
| |
| SkString GrBackendFormat::toStr() const { |
| SkString str; |
| |
| if (!fValid) { |
| str.append("invalid"); |
| return str; |
| } |
| |
| str.appendf("%s-", GrBackendApiToStr(fBackend)); |
| |
| switch (fBackend) { |
| case GrBackendApi::kOpenGL: |
| case GrBackendApi::kVulkan: |
| case GrBackendApi::kMetal: |
| str.append(fFormatData->toString()); |
| break; |
| case GrBackendApi::kDirect3D: |
| #ifdef SK_DIRECT3D |
| str.append(GrDxgiFormatToStr(fDxgiFormat)); |
| #endif |
| break; |
| case GrBackendApi::kMock: |
| str.append(GrColorTypeToStr(fMock.fColorType)); |
| str.appendf("-"); |
| str.append(skgpu::CompressionTypeToStr(fMock.fCompressionType)); |
| break; |
| case GrBackendApi::kUnsupported: |
| break; |
| } |
| |
| return str; |
| } |
| #endif |
| |
| /////////////////////////////////////////////////////////////////////////////////////////////////// |
| GrBackendTexture::GrBackendTexture() : fIsValid(false) {} |
| |
| #ifdef SK_DIRECT3D |
| GrBackendTexture::GrBackendTexture(int width, |
| int height, |
| const GrD3DTextureResourceInfo& d3dInfo, |
| std::string_view label) |
| : GrBackendTexture(width, |
| height, |
| d3dInfo, |
| sk_sp<GrD3DResourceState>(new GrD3DResourceState( |
| static_cast<D3D12_RESOURCE_STATES>(d3dInfo.fResourceState))), |
| label) {} |
| |
| GrBackendTexture::GrBackendTexture(int width, |
| int height, |
| const GrD3DTextureResourceInfo& d3dInfo, |
| sk_sp<GrD3DResourceState> state, |
| std::string_view label) |
| : fIsValid(true) |
| , fWidth(width) |
| , fHeight(height) |
| , fLabel(label) |
| , fMipmapped(skgpu::Mipmapped(d3dInfo.fLevelCount > 1)) |
| , fBackend(GrBackendApi::kDirect3D) |
| , fTextureType(GrTextureType::k2D) |
| , fD3DInfo(d3dInfo, state.release()) {} |
| #endif |
| |
| GrBackendTexture::GrBackendTexture(int width, |
| int height, |
| skgpu::Mipmapped mipmapped, |
| const GrMockTextureInfo& mockInfo, |
| std::string_view label) |
| : fIsValid(true) |
| , fWidth(width) |
| , fHeight(height) |
| , fLabel(label) |
| , fMipmapped(mipmapped) |
| , fBackend(GrBackendApi::kMock) |
| , fTextureType(GrTextureType::k2D) |
| , fMockInfo(mockInfo) {} |
| |
| GrBackendTexture::~GrBackendTexture() { |
| this->cleanup(); |
| } |
| |
| void GrBackendTexture::cleanup() { |
| fTextureData.reset(); |
| #ifdef SK_DIRECT3D |
| if (this->isValid() && GrBackendApi::kDirect3D == fBackend) { |
| fD3DInfo.cleanup(); |
| } |
| #endif |
| } |
| |
| GrBackendTexture::GrBackendTexture(const GrBackendTexture& that) : fIsValid(false) { |
| *this = that; |
| } |
| |
| GrBackendTexture& GrBackendTexture::operator=(const GrBackendTexture& that) { |
| if (this == &that) { |
| return *this; |
| } |
| |
| if (!that.isValid()) { |
| this->cleanup(); |
| fIsValid = false; |
| return *this; |
| } else if (fIsValid && this->fBackend != that.fBackend) { |
| this->cleanup(); |
| fIsValid = false; |
| } |
| fWidth = that.fWidth; |
| fHeight = that.fHeight; |
| fMipmapped = that.fMipmapped; |
| fBackend = that.fBackend; |
| fTextureType = that.fTextureType; |
| |
| switch (that.fBackend) { |
| case GrBackendApi::kOpenGL: |
| case GrBackendApi::kVulkan: |
| case GrBackendApi::kMetal: |
| fTextureData.reset(); |
| that.fTextureData->copyTo(fTextureData); |
| break; |
| #ifdef SK_DIRECT3D |
| case GrBackendApi::kDirect3D: |
| fD3DInfo.assign(that.fD3DInfo, this->isValid()); |
| break; |
| #endif |
| case GrBackendApi::kMock: |
| fMockInfo = that.fMockInfo; |
| break; |
| default: |
| SK_ABORT("Unknown GrBackend"); |
| } |
| fIsValid = true; |
| return *this; |
| } |
| |
| sk_sp<skgpu::MutableTextureState> GrBackendTexture::getMutableState() const { |
| return fTextureData->getMutableState(); |
| } |
| |
| #ifdef SK_DIRECT3D |
| bool GrBackendTexture::getD3DTextureResourceInfo(GrD3DTextureResourceInfo* outInfo) const { |
| if (this->isValid() && GrBackendApi::kDirect3D == fBackend) { |
| *outInfo = fD3DInfo.snapTextureResourceInfo(); |
| return true; |
| } |
| return false; |
| } |
| |
| void GrBackendTexture::setD3DResourceState(GrD3DResourceStateEnum state) { |
| if (this->isValid() && GrBackendApi::kDirect3D == fBackend) { |
| fD3DInfo.setResourceState(state); |
| } |
| } |
| |
| sk_sp<GrD3DResourceState> GrBackendTexture::getGrD3DResourceState() const { |
| if (this->isValid() && GrBackendApi::kDirect3D == fBackend) { |
| return fD3DInfo.getGrD3DResourceState(); |
| } |
| return nullptr; |
| } |
| #endif |
| |
| bool GrBackendTexture::getMockTextureInfo(GrMockTextureInfo* outInfo) const { |
| if (this->isValid() && GrBackendApi::kMock == fBackend) { |
| *outInfo = fMockInfo; |
| return true; |
| } |
| return false; |
| } |
| |
| void GrBackendTexture::setMutableState(const skgpu::MutableTextureState& state) { |
| fTextureData->setMutableState(state); |
| } |
| |
| bool GrBackendTexture::isProtected() const { |
| if (!this->isValid()) { |
| return false; |
| } |
| if (this->backend() == GrBackendApi::kOpenGL || this->backend() == GrBackendApi::kVulkan) { |
| return fTextureData->isProtected(); |
| } |
| if (this->backend() == GrBackendApi::kMock) { |
| return fMockInfo.isProtected(); |
| } |
| |
| return false; |
| } |
| |
| bool GrBackendTexture::isSameTexture(const GrBackendTexture& that) { |
| if (!this->isValid() || !that.isValid()) { |
| return false; |
| } |
| if (fBackend != that.fBackend) { |
| return false; |
| } |
| switch (fBackend) { |
| case GrBackendApi::kOpenGL: |
| case GrBackendApi::kVulkan: |
| case GrBackendApi::kMetal: |
| return fTextureData->isSameTexture(that.fTextureData.get()); |
| #ifdef SK_DIRECT3D |
| case GrBackendApi::kDirect3D: |
| return fD3DInfo.snapTextureResourceInfo().fResource == |
| that.fD3DInfo.snapTextureResourceInfo().fResource; |
| #endif |
| case GrBackendApi::kMock: |
| return fMockInfo.id() == that.fMockInfo.id(); |
| default: |
| return false; |
| } |
| } |
| |
| GrBackendFormat GrBackendTexture::getBackendFormat() const { |
| if (!this->isValid()) { |
| return GrBackendFormat(); |
| } |
| switch (fBackend) { |
| case GrBackendApi::kOpenGL: |
| case GrBackendApi::kVulkan: |
| case GrBackendApi::kMetal: |
| return fTextureData->getBackendFormat(); |
| #ifdef SK_DIRECT3D |
| case GrBackendApi::kDirect3D: { |
| auto d3dInfo = fD3DInfo.snapTextureResourceInfo(); |
| return GrBackendFormat::MakeDxgi(d3dInfo.fFormat); |
| } |
| #endif |
| case GrBackendApi::kMock: |
| return fMockInfo.getBackendFormat(); |
| default: |
| return GrBackendFormat(); |
| } |
| } |
| |
| #if defined(GR_TEST_UTILS) |
| bool GrBackendTexture::TestingOnly_Equals(const GrBackendTexture& t0, const GrBackendTexture& t1) { |
| if (!t0.isValid() || !t1.isValid()) { |
| return false; // two invalid backend textures are not considered equal |
| } |
| |
| if (t0.fWidth != t1.fWidth || |
| t0.fHeight != t1.fHeight || |
| t0.fMipmapped != t1.fMipmapped || |
| t0.fBackend != t1.fBackend) { |
| return false; |
| } |
| |
| switch (t0.fBackend) { |
| case GrBackendApi::kOpenGL: |
| case GrBackendApi::kVulkan: |
| case GrBackendApi::kMetal: |
| return t0.fTextureData->equal(t1.fTextureData.get()); |
| case GrBackendApi::kMock: |
| return t0.fMockInfo == t1.fMockInfo; |
| #ifdef SK_DIRECT3D |
| case GrBackendApi::kDirect3D: |
| return t0.fD3DInfo == t1.fD3DInfo; |
| #endif |
| default: |
| return false; |
| } |
| } |
| #endif |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| GrBackendRenderTarget::GrBackendRenderTarget() : fIsValid(false) {} |
| |
| #ifdef SK_DIRECT3D |
| GrBackendRenderTarget::GrBackendRenderTarget(int width, int height, |
| const GrD3DTextureResourceInfo& d3dInfo) |
| : GrBackendRenderTarget( |
| width, height, d3dInfo, |
| sk_sp<GrD3DResourceState>(new GrD3DResourceState( |
| static_cast<D3D12_RESOURCE_STATES>(d3dInfo.fResourceState)))) {} |
| |
| GrBackendRenderTarget::GrBackendRenderTarget(int width, |
| int height, |
| const GrD3DTextureResourceInfo& d3dInfo, |
| sk_sp<GrD3DResourceState> state) |
| : fIsValid(true) |
| , fWidth(width) |
| , fHeight(height) |
| , fSampleCnt(std::max(1U, d3dInfo.fSampleCount)) |
| , fStencilBits(0) |
| , fBackend(GrBackendApi::kDirect3D) |
| , fD3DInfo(d3dInfo, state.release()) {} |
| #endif |
| |
| GrBackendRenderTarget::GrBackendRenderTarget(int width, |
| int height, |
| int sampleCnt, |
| int stencilBits, |
| const GrMockRenderTargetInfo& mockInfo) |
| : fIsValid(true) |
| , fWidth(width) |
| , fHeight(height) |
| , fSampleCnt(std::max(1, sampleCnt)) |
| , fStencilBits(stencilBits) |
| , fBackend(GrBackendApi::kMock) |
| , fMockInfo(mockInfo) {} |
| |
| GrBackendRenderTarget::~GrBackendRenderTarget() { |
| this->cleanup(); |
| } |
| |
| void GrBackendRenderTarget::cleanup() { |
| fRTData.reset(); |
| #ifdef SK_DIRECT3D |
| if (this->isValid() && GrBackendApi::kDirect3D == fBackend) { |
| fD3DInfo.cleanup(); |
| } |
| #endif |
| } |
| |
| GrBackendRenderTarget::GrBackendRenderTarget(const GrBackendRenderTarget& that) : fIsValid(false) { |
| *this = that; |
| } |
| |
| GrBackendRenderTarget& GrBackendRenderTarget::operator=(const GrBackendRenderTarget& that) { |
| if (this == &that) { |
| return *this; |
| } |
| |
| if (!that.isValid()) { |
| this->cleanup(); |
| fIsValid = false; |
| return *this; |
| } else if (fIsValid && this->fBackend != that.fBackend) { |
| this->cleanup(); |
| fIsValid = false; |
| } |
| fWidth = that.fWidth; |
| fHeight = that.fHeight; |
| fSampleCnt = that.fSampleCnt; |
| fStencilBits = that.fStencilBits; |
| fBackend = that.fBackend; |
| |
| switch (that.fBackend) { |
| case GrBackendApi::kOpenGL: |
| case GrBackendApi::kVulkan: |
| case GrBackendApi::kMetal: |
| fRTData.reset(); |
| that.fRTData->copyTo(fRTData); |
| break; |
| #ifdef SK_DIRECT3D |
| case GrBackendApi::kDirect3D: |
| fD3DInfo.assign(that.fD3DInfo, this->isValid()); |
| break; |
| #endif |
| case GrBackendApi::kMock: |
| fMockInfo = that.fMockInfo; |
| break; |
| default: |
| SK_ABORT("Unknown GrBackend"); |
| } |
| fIsValid = that.fIsValid; |
| return *this; |
| } |
| |
| sk_sp<skgpu::MutableTextureState> GrBackendRenderTarget::getMutableState() const { |
| return fRTData->getMutableState(); |
| } |
| |
| #ifdef SK_DIRECT3D |
| bool GrBackendRenderTarget::getD3DTextureResourceInfo(GrD3DTextureResourceInfo* outInfo) const { |
| if (this->isValid() && GrBackendApi::kDirect3D == fBackend) { |
| *outInfo = fD3DInfo.snapTextureResourceInfo(); |
| return true; |
| } |
| return false; |
| } |
| |
| void GrBackendRenderTarget::setD3DResourceState(GrD3DResourceStateEnum state) { |
| if (this->isValid() && GrBackendApi::kDirect3D == fBackend) { |
| fD3DInfo.setResourceState(state); |
| } |
| } |
| |
| sk_sp<GrD3DResourceState> GrBackendRenderTarget::getGrD3DResourceState() const { |
| if (this->isValid() && GrBackendApi::kDirect3D == fBackend) { |
| return fD3DInfo.getGrD3DResourceState(); |
| } |
| return nullptr; |
| } |
| #endif |
| |
| GrBackendFormat GrBackendRenderTarget::getBackendFormat() const { |
| if (!this->isValid()) { |
| return GrBackendFormat(); |
| } |
| switch (fBackend) { |
| case GrBackendApi::kOpenGL: |
| case GrBackendApi::kVulkan: |
| case GrBackendApi::kMetal: |
| return fRTData->getBackendFormat(); |
| #ifdef SK_DIRECT3D |
| case GrBackendApi::kDirect3D: { |
| auto info = fD3DInfo.snapTextureResourceInfo(); |
| return GrBackendFormat::MakeDxgi(info.fFormat); |
| } |
| #endif |
| case GrBackendApi::kMock: |
| return fMockInfo.getBackendFormat(); |
| default: |
| return GrBackendFormat(); |
| } |
| } |
| |
| bool GrBackendRenderTarget::getMockRenderTargetInfo(GrMockRenderTargetInfo* outInfo) const { |
| if (this->isValid() && GrBackendApi::kMock == fBackend) { |
| *outInfo = fMockInfo; |
| return true; |
| } |
| return false; |
| } |
| |
| void GrBackendRenderTarget::setMutableState(const skgpu::MutableTextureState& state) { |
| fRTData->setMutableState(state); |
| } |
| |
| bool GrBackendRenderTarget::isProtected() const { |
| if (!this->isValid()) { |
| return false; |
| } |
| if (this->backend() == GrBackendApi::kOpenGL || this->backend() == GrBackendApi::kVulkan) { |
| return fRTData->isProtected(); |
| } |
| if (this->backend() == GrBackendApi::kMock) { |
| return fMockInfo.isProtected(); |
| } |
| |
| return false; |
| } |
| |
| #if defined(GR_TEST_UTILS) |
| bool GrBackendRenderTarget::TestingOnly_Equals(const GrBackendRenderTarget& r0, |
| const GrBackendRenderTarget& r1) { |
| if (!r0.isValid() || !r1.isValid()) { |
| return false; // two invalid backend rendertargets are not considered equal |
| } |
| |
| if (r0.fWidth != r1.fWidth || |
| r0.fHeight != r1.fHeight || |
| r0.fSampleCnt != r1.fSampleCnt || |
| r0.fStencilBits != r1.fStencilBits || |
| r0.fBackend != r1.fBackend) { |
| return false; |
| } |
| |
| switch (r0.fBackend) { |
| case GrBackendApi::kOpenGL: |
| case GrBackendApi::kVulkan: |
| case GrBackendApi::kMetal: |
| return r0.fRTData->equal(r1.fRTData.get()); |
| case GrBackendApi::kMock: |
| return r0.fMockInfo == r1.fMockInfo; |
| #ifdef SK_DIRECT3D |
| case GrBackendApi::kDirect3D: |
| return r0.fD3DInfo == r1.fD3DInfo; |
| #endif |
| default: |
| return false; |
| } |
| |
| SkASSERT(0); |
| return false; |
| } |
| #endif |
| |
| GrBackendFormatData::~GrBackendFormatData() {} |
| GrBackendTextureData::~GrBackendTextureData() {} |
| GrBackendRenderTargetData::~GrBackendRenderTargetData() {} |