Fill in the D3DTexture class.

Bug: skia:9935
Change-Id: Idd37e677462fec7ed0beca0fe578fb1a2f497eb8
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/278784
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
Jim Van Verth 2020-03-24 14:58:03 -04:00 committed by Skia Commit-Bot
parent 7a5f1fa1fb
commit 8b932b157b
7 changed files with 494 additions and 137 deletions

View File

@ -743,11 +743,13 @@ skia_direct3d_sources = [
"$_src/gpu/d3d/GrD3DGpu.h",
"$_src/gpu/d3d/GrD3DOpsRenderPass.cpp",
"$_src/gpu/d3d/GrD3DOpsRenderPass.h",
"$_src/gpu/d3d/GrD3DResource.cpp",
"$_src/gpu/d3d/GrD3DResource.h",
"$_src/gpu/d3d/GrD3DResourceProvider.cpp",
"$_src/gpu/d3d/GrD3DResourceProvider.h",
"$_src/gpu/d3d/GrD3DResourceState.h",
"$_src/gpu/d3d/GrD3DSurfaceResource.cpp",
"$_src/gpu/d3d/GrD3DSurfaceResource.h",
"$_src/gpu/d3d/GrD3DTexture.cpp",
"$_src/gpu/d3d/GrD3DTexture.h",
"$_src/gpu/d3d/GrD3DTypesPriv.cpp",
"$_src/gpu/d3d/GrD3DUtil.cpp",
"$_src/gpu/d3d/GrD3DUtil.h",

View File

@ -1,57 +0,0 @@
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/GrGpuResourcePriv.h"
#include "src/gpu/d3d/GrD3DGpu.h"
#include "src/gpu/d3d/GrD3DResource.h"
void GrD3DResource::setResourceState(const GrD3DGpu* gpu,
D3D12_RESOURCE_STATES newResourceState) {
SkASSERT(fStateExplicitlySet);
/* TODO
* Something like:
D3D12_RESOURCE_STATES currentState = this->currentState();
gpu->addResourceTransitionBarrier(this->resource(), currentState, newResourceState);
*/
this->updateResourceState(newResourceState, true);
}
ID3D12Resource* GrD3DResource::CreateResource(GrD3DGpu* gpu, const D3D12_RESOURCE_DESC& desc,
D3D12_RESOURCE_STATES resourceState) {
ID3D12Resource* resource = nullptr;
// TODO: incorporate D3Dx12.h and use CD3DX12_HEAP_PROPERTIES instead?
D3D12_HEAP_PROPERTIES heapProperties = {
D3D12_HEAP_TYPE_DEFAULT,
D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
D3D12_MEMORY_POOL_UNKNOWN,
1, // CreationNodeMask
1 // VisibleNodeMask
};
SkDEBUGCODE(HRESULT hr =) gpu->device()->CreateCommittedResource(
&heapProperties,
D3D12_HEAP_FLAG_NONE,
&desc,
resourceState,
nullptr,
IID_PPV_ARGS(&resource));
SkASSERT(SUCCEEDED(hr));
return resource;
}
GrD3DResource::~GrD3DResource() {
// should have been released first
SkASSERT(!fResource);
}
void GrD3DResource::releaseResource() {
if (fResource) {
fResource->Release();
fResource = nullptr;
}
}

View File

@ -1,78 +0,0 @@
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrD3DResource_DEFINED
#define GrD3DResource_DEFINED
#include "include/core/SkTypes.h"
#include "include/gpu/GrBackendSurface.h"
#include "include/private/GrTypesPriv.h"
#include "src/gpu/d3d/GrD3D12.h"
#include "src/gpu/d3d/GrD3DResourceState.h"
class GrD3DGpu;
class GrD3DResource : SkNoncopyable {
public:
GrD3DResource(ID3D12Resource* resource, const D3D12_RESOURCE_DESC& desc,
sk_sp<GrD3DResourceState> state,
GrBackendObjectOwnership ownership = GrBackendObjectOwnership::kOwned)
: fDesc(desc)
, fState(std::move(state))
, fStateExplicitlySet(true)
, fIsBorrowed(GrBackendObjectOwnership::kBorrowed == ownership)
, fResource(resource) {
if (fIsBorrowed) {
fResource->AddRef();
}
}
virtual ~GrD3DResource();
const ID3D12Resource* resource() const {
SkASSERT(fResource);
return fResource;
}
DXGI_FORMAT dxgiFormat() const { return fDesc.Format; }
GrBackendFormat getBackendFormat() const {
return GrBackendFormat::MakeDxgi(this->dxgiFormat());
}
uint32_t mipLevels() const { return fDesc.MipLevels; }
bool isBorrowed() const { return fIsBorrowed; }
sk_sp<GrD3DResourceState> grD3DResourceState() const { return fState; }
D3D12_RESOURCE_STATES currentState() const {
return fState->getResourceState();
}
void setResourceState(const GrD3DGpu* gpu,
D3D12_RESOURCE_STATES newResourceState);
// This simply updates our tracking of the resourceState and does not actually do any gpu work.
// Externally, primarily used for implicit changes in resourceState due to certain GPU commands.
void updateResourceState(D3D12_RESOURCE_STATES newState, bool explicitlySet) {
SkASSERT(fResource);
fState->setResourceState(newState);
}
static ID3D12Resource* CreateResource(GrD3DGpu* gpu, const D3D12_RESOURCE_DESC& desc,
D3D12_RESOURCE_STATES resourceState);
protected:
void releaseResource();
bool hasResource() const { return SkToBool(fResource); }
D3D12_RESOURCE_DESC fDesc;
sk_sp<GrD3DResourceState> fState;
bool fStateExplicitlySet;
bool fIsBorrowed;
private:
ID3D12Resource* fResource;
};
#endif

View File

@ -0,0 +1,93 @@
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/GrGpuResourcePriv.h"
#include "src/gpu/d3d/GrD3DGpu.h"
#include "src/gpu/d3d/GrD3DSurfaceResource.h"
void GrD3DSurfaceResource::setResourceState(const GrD3DGpu* gpu,
D3D12_RESOURCE_STATES newResourceState) {
SkASSERT(fStateExplicitlySet);
/* TODO
* Something like:
D3D12_RESOURCE_STATES currentState = this->currentState();
gpu->addResourceTransitionBarrier(this->resource(), currentState, newResourceState);
*/
this->updateResourceState(newResourceState, true);
}
bool GrD3DSurfaceResource::InitTextureInfo(GrD3DGpu* gpu, const D3D12_RESOURCE_DESC& desc,
GrProtected isProtected, GrD3DTextureInfo* info) {
if (0 == desc.Width || 0 == desc.Height) {
return false;
}
// TODO: We don't support protected memory at the moment
if (isProtected == GrProtected::kYes) {
return false;
}
// If MipLevels is 0, for some formats the API will automatically calculate the maximum
// number of levels supported and use that -- we don't support that.
SkASSERT(desc.MipLevels > 0);
ID3D12Resource* resource = nullptr;
// TODO: incorporate D3Dx12.h and use CD3DX12_HEAP_PROPERTIES instead?
D3D12_HEAP_PROPERTIES heapProperties = {
D3D12_HEAP_TYPE_DEFAULT,
D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
D3D12_MEMORY_POOL_UNKNOWN,
1, // CreationNodeMask
1 // VisibleNodeMask
};
HRESULT hr = gpu->device()->CreateCommittedResource(
&heapProperties,
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_COMMON,
nullptr,
IID_PPV_ARGS(&resource));
if (!SUCCEEDED(hr)) {
return false;
}
info->fTexture = resource;
info->fResourceState = D3D12_RESOURCE_STATE_COMMON;
info->fFormat = desc.Format;
info->fLevelCount = desc.MipLevels;
info->fProtected = isProtected;
return true;
}
void GrD3DSurfaceResource::DestroyTextureInfo(GrD3DTextureInfo* info) {
info->fTexture->Release();
}
GrD3DSurfaceResource::~GrD3DSurfaceResource() {
// should have been released first
SkASSERT(!fResource);
}
void GrD3DSurfaceResource::releaseTexture(GrD3DGpu* gpu) {
// TODO: do we need to migrate resource state if we change queues?
if (fResource) {
fResource->removeOwningTexture();
fResource->unref();
fResource = nullptr;
}
}
void GrD3DSurfaceResource::setResourceRelease(sk_sp<GrRefCntedCallback> releaseHelper) {
SkASSERT(fResource);
// Forward the release proc on to GrD3DSurfaceResource::Resource
fResource->setRelease(std::move(releaseHelper));
}
void GrD3DSurfaceResource::Resource::freeGPUData() const {
this->invokeReleaseProc();
fResource->Release();
}

View File

@ -0,0 +1,112 @@
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrD3DSurfaceResource_DEFINED
#define GrD3DSurfaceResource_DEFINED
#include "include/core/SkTypes.h"
#include "include/gpu/GrBackendSurface.h"
#include "include/private/GrTypesPriv.h"
#include "src/gpu/GrManagedResource.h"
#include "src/gpu/d3d/GrD3D12.h"
#include "src/gpu/d3d/GrD3DResourceState.h"
class GrD3DGpu;
class GrD3DSurfaceResource : SkNoncopyable {
private:
class Resource;
public:
GrD3DSurfaceResource(const GrD3DTextureInfo& info, sk_sp<GrD3DResourceState> state,
GrBackendObjectOwnership ownership = GrBackendObjectOwnership::kOwned)
: fInfo(info)
, fState(std::move(state))
, fStateExplicitlySet(true)
, fIsBorrowed(GrBackendObjectOwnership::kBorrowed == ownership)
, fResource(new Resource(fInfo.fTexture)) {
if (fIsBorrowed) {
fInfo.fTexture->AddRef();
}
}
virtual ~GrD3DSurfaceResource();
const Resource* resource() const {
SkASSERT(fResource);
return fResource.get();
}
DXGI_FORMAT dxgiFormat() const { return fInfo.fFormat; }
GrBackendFormat getBackendFormat() const {
return GrBackendFormat::MakeDxgi(this->dxgiFormat());
}
uint32_t mipLevels() const { return fInfo.fLevelCount; }
bool isBorrowed() const { return fIsBorrowed; }
sk_sp<GrD3DResourceState> grD3DResourceState() const { return fState; }
D3D12_RESOURCE_STATES currentState() const {
return fState->getResourceState();
}
void setResourceState(const GrD3DGpu* gpu, D3D12_RESOURCE_STATES newResourceState);
// This simply updates our tracking of the resourceState and does not actually do any gpu work.
// Externally, primarily used for implicit changes in resourceState due to certain GPU commands.
void updateResourceState(D3D12_RESOURCE_STATES newState, bool explicitlySet) {
SkASSERT(fResource);
fState->setResourceState(newState);
fStateExplicitlySet = explicitlySet;
}
static bool InitTextureInfo(GrD3DGpu* gpu, const D3D12_RESOURCE_DESC& desc, GrProtected,
GrD3DTextureInfo*);
// Destroys the internal ID3D12Resource in the GrD3DTextureInfo
static void DestroyTextureInfo(GrD3DTextureInfo*);
void setResourceRelease(sk_sp<GrRefCntedCallback> releaseHelper);
protected:
void releaseTexture(GrD3DGpu* gpu);
bool hasResource() const { return SkToBool(fResource); }
GrD3DTextureInfo fInfo;
sk_sp<GrD3DResourceState> fState;
bool fStateExplicitlySet;
bool fIsBorrowed;
private:
class Resource : public GrTextureResource {
public:
explicit Resource()
: fResource(nullptr) {
}
Resource(ID3D12Resource* textureResource)
: fResource(textureResource) {
fResource->AddRef();
}
~Resource() override {}
#ifdef SK_TRACE_MANAGED_RESOURCES
void dumpInfo() const override {
SkDebugf("GrD3DSurfaceResource: %d (%d refs)\n", fResource, this->getRefCnt());
}
#endif
private:
void freeGPUData() const override;
ID3D12Resource* fResource;
typedef GrTextureResource INHERITED;
};
sk_sp<Resource> fResource;
};
#endif

View File

@ -0,0 +1,198 @@
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/d3d/GrD3DTexture.h"
#include "src/gpu/GrTexturePriv.h"
#include "src/gpu/d3d/GrD3DGpu.h"
#include "src/gpu/d3d/GrD3DUtil.h"
#include "include/gpu/d3d/GrD3DTypes.h"
// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrD3DTexture::GrD3DTexture(GrD3DGpu* gpu,
SkBudgeted budgeted,
SkISize dimensions,
const GrD3DTextureInfo& info,
sk_sp<GrD3DResourceState> state,
GrMipMapsStatus mipMapsStatus)
: GrSurface(gpu, dimensions, info.fProtected)
, GrD3DSurfaceResource(info, std::move(state), GrBackendObjectOwnership::kOwned)
, INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus) {
SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
this->registerWithCache(budgeted);
if (GrDxgiFormatIsCompressed(info.fFormat)) {
this->setReadOnly();
}
}
GrD3DTexture::GrD3DTexture(GrD3DGpu* gpu, SkISize dimensions, const GrD3DTextureInfo& info,
sk_sp<GrD3DResourceState> state, GrMipMapsStatus mipMapsStatus,
GrBackendObjectOwnership ownership, GrWrapCacheable cacheable,
GrIOType ioType)
: GrSurface(gpu, dimensions, info.fProtected)
, GrD3DSurfaceResource(info, std::move(state), ownership)
, INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus) {
SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
if (ioType == kRead_GrIOType) {
this->setReadOnly();
}
this->registerWithCacheWrapped(cacheable);
}
// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrD3DTexture::GrD3DTexture(GrD3DGpu* gpu,
SkISize dimensions,
const GrD3DTextureInfo& info,
sk_sp<GrD3DResourceState> state,
GrMipMapsStatus mipMapsStatus,
GrBackendObjectOwnership ownership)
: GrSurface(gpu, dimensions, info.fProtected)
, GrD3DSurfaceResource(info, state, ownership)
, INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus) {
SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
}
sk_sp<GrD3DTexture> GrD3DTexture::MakeNewTexture(GrD3DGpu* gpu, SkBudgeted budgeted,
SkISize dimensions,
const D3D12_RESOURCE_DESC& desc,
GrProtected isProtected,
GrMipMapsStatus mipMapsStatus) {
GrD3DTextureInfo info;
if (!GrD3DSurfaceResource::InitTextureInfo(gpu, desc, isProtected, &info)) {
return nullptr;
}
sk_sp<GrD3DResourceState> state(
new GrD3DResourceState(static_cast<D3D12_RESOURCE_STATES>(info.fResourceState)));
return sk_sp<GrD3DTexture>(new GrD3DTexture(gpu, budgeted, dimensions, info, std::move(state),
mipMapsStatus));
}
sk_sp<GrD3DTexture> GrD3DTexture::MakeWrappedTexture(GrD3DGpu* gpu,
SkISize dimensions,
GrWrapOwnership wrapOwnership,
GrWrapCacheable cacheable,
GrIOType ioType,
const GrD3DTextureInfo& info,
sk_sp<GrD3DResourceState> state) {
// TODO: If a client uses their own heap to allocate, how do we manage that?
// Adopted textures require both image and allocation because we're responsible for freeing
//SkASSERT(info.fTexture &&
// (kBorrow_GrWrapOwnership == wrapOwnership || VK_NULL_HANDLE != info.fAlloc.fMemory));
GrMipMapsStatus mipMapsStatus = info.fLevelCount > 1 ? GrMipMapsStatus::kValid
: GrMipMapsStatus::kNotAllocated;
GrBackendObjectOwnership ownership = kBorrow_GrWrapOwnership == wrapOwnership
? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned;
return sk_sp<GrD3DTexture>(new GrD3DTexture(gpu, dimensions, info, std::move(state),
mipMapsStatus, ownership, cacheable, ioType));
}
void GrD3DTexture::onRelease() {
// We're about to be severed from our GrManagedResource. If there are "finish" idle procs we
// have to decide who will handle them. If the resource is still tied to a command buffer we let
// it handle them. Otherwise, we handle them.
if (this->hasResource() && this->resource()->isQueuedForWorkOnGpu()) {
this->removeFinishIdleProcs();
}
this->releaseTexture(this->getD3DGpu());
INHERITED::onRelease();
}
void GrD3DTexture::onAbandon() {
// We're about to be severed from our GrManagedResource. If there are "finish" idle procs we
// have to decide who will handle them. If the resource is still tied to a command buffer we let
// it handle them. Otherwise, we handle them.
if (this->hasResource() && this->resource()->isQueuedForWorkOnGpu()) {
this->removeFinishIdleProcs();
}
this->releaseTexture(this->getD3DGpu());
INHERITED::onAbandon();
}
GrBackendTexture GrD3DTexture::getBackendTexture() const {
return GrBackendTexture(this->width(), this->height(), fInfo, this->grD3DResourceState());
}
GrD3DGpu* GrD3DTexture::getD3DGpu() const {
SkASSERT(!this->wasDestroyed());
return static_cast<GrD3DGpu*>(this->getGpu());
}
void GrD3DTexture::addIdleProc(sk_sp<GrRefCntedCallback> idleProc, IdleState type) {
INHERITED::addIdleProc(idleProc, type);
if (type == IdleState::kFinished) {
if (auto* resource = this->resource()) {
resource->addIdleProc(this, std::move(idleProc));
}
}
}
void GrD3DTexture::callIdleProcsOnBehalfOfResource() {
// If we got here then the resource is being removed from its last command buffer and the
// texture is idle in the cache. Any kFlush idle procs should already have been called. So
// the texture and resource should have the same set of procs.
SkASSERT(this->resource());
SkASSERT(this->resource()->idleProcCnt() == fIdleProcs.count());
#ifdef SK_DEBUG
for (int i = 0; i < fIdleProcs.count(); ++i) {
SkASSERT(fIdleProcs[i] == this->resource()->idleProc(i));
}
#endif
fIdleProcs.reset();
this->resource()->resetIdleProcs();
}
void GrD3DTexture::willRemoveLastRef() {
if (!fIdleProcs.count()) {
return;
}
// This is called when the GrTexture is purgeable. However, we need to check whether the
// Resource is still owned by any command buffers. If it is then it will call the proc.
auto* resource = this->hasResource() ? this->resource() : nullptr;
bool callFinishProcs = !resource || !resource->isQueuedForWorkOnGpu();
if (callFinishProcs) {
// Everything must go!
fIdleProcs.reset();
resource->resetIdleProcs();
} else {
// The procs that should be called on flush but not finish are those that are owned
// by the GrD3DTexture and not the Resource. We do this by copying the resource's array
// and thereby dropping refs to procs we own but the resource does not.
SkASSERT(resource);
fIdleProcs.reset(resource->idleProcCnt());
for (int i = 0; i < fIdleProcs.count(); ++i) {
fIdleProcs[i] = resource->idleProc(i);
}
}
}
void GrD3DTexture::removeFinishIdleProcs() {
// This should only be called by onRelease/onAbandon when we have already checked for a
// resource.
const auto* resource = this->resource();
SkASSERT(resource);
SkSTArray<4, sk_sp<GrRefCntedCallback>> procsToKeep;
int resourceIdx = 0;
// The idle procs that are common between the GrD3DTexture and its Resource should be found in
// the same order.
for (int i = 0; i < fIdleProcs.count(); ++i) {
if (fIdleProcs[i] == resource->idleProc(resourceIdx)) {
++resourceIdx;
} else {
procsToKeep.push_back(fIdleProcs[i]);
}
}
SkASSERT(resourceIdx == resource->idleProcCnt());
fIdleProcs = procsToKeep;
}

View File

@ -0,0 +1,87 @@
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrD3DTexture_DEFINED
#define GrD3DTexture_DEFINED
#include "src/core/SkLRUCache.h"
#include "src/gpu/GrSamplerState.h"
#include "src/gpu/GrTexture.h"
#include "src/gpu/d3d/GrD3DSurfaceResource.h"
class GrD3DTexture : public GrTexture, public virtual GrD3DSurfaceResource {
public:
static sk_sp<GrD3DTexture> MakeNewTexture(GrD3DGpu*,
SkBudgeted,
SkISize dimensions,
const D3D12_RESOURCE_DESC&,
GrProtected,
GrMipMapsStatus);
static sk_sp<GrD3DTexture> MakeWrappedTexture(GrD3DGpu*,
SkISize dimensions,
GrWrapOwnership,
GrWrapCacheable,
GrIOType,
const GrD3DTextureInfo&,
sk_sp<GrD3DResourceState>);
~GrD3DTexture() override {}
GrBackendTexture getBackendTexture() const override;
GrBackendFormat backendFormat() const override { return this->getBackendFormat(); }
void textureParamsModified() override {}
void addIdleProc(sk_sp<GrRefCntedCallback>, IdleState) override;
void callIdleProcsOnBehalfOfResource() override;
protected:
GrD3DTexture(GrD3DGpu*,
SkISize dimensions,
const GrD3DTextureInfo&,
sk_sp<GrD3DResourceState>,
GrMipMapsStatus,
GrBackendObjectOwnership);
GrD3DGpu* getD3DGpu() const;
void onAbandon() override;
void onRelease() override;
bool onStealBackendTexture(GrBackendTexture*, SkImage::BackendTextureReleaseProc*) override {
return false;
}
void willRemoveLastRef() override;
private:
GrD3DTexture(GrD3DGpu*, SkBudgeted, SkISize dimensions, const GrD3DTextureInfo&,
sk_sp<GrD3DResourceState>, GrMipMapsStatus);
GrD3DTexture(GrD3DGpu*, SkISize dimensions, const GrD3DTextureInfo&, sk_sp<GrD3DResourceState>,
GrMipMapsStatus, GrBackendObjectOwnership, GrWrapCacheable, GrIOType);
// In D3D we call the release proc after we are finished with the underlying
// GrSurfaceResource::Resource object (which occurs after the GPU has finished all work on it).
void onSetRelease(sk_sp<GrRefCntedCallback> releaseHelper) override {
// Forward the release proc on to GrSurfaceResource
this->setResourceRelease(std::move(releaseHelper));
}
void removeFinishIdleProcs();
struct SamplerHash {
uint32_t operator()(GrSamplerState state) const {
return GrSamplerState::GenerateKey(state);
}
};
typedef GrTexture INHERITED;
};
#endif