1 /*
2 * Copyright 2020 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/d3d/GrD3DTexture.h"
9
10 #include "src/gpu/GrTexturePriv.h"
11 #include "src/gpu/d3d/GrD3DGpu.h"
12 #include "src/gpu/d3d/GrD3DUtil.h"
13
14 #include "include/gpu/d3d/GrD3DTypes.h"
15
16 // Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrD3DTexture(GrD3DGpu * gpu,SkBudgeted budgeted,SkISize dimensions,const GrD3DTextureResourceInfo & info,sk_sp<GrD3DResourceState> state,GrMipMapsStatus mipMapsStatus)17 GrD3DTexture::GrD3DTexture(GrD3DGpu* gpu,
18 SkBudgeted budgeted,
19 SkISize dimensions,
20 const GrD3DTextureResourceInfo& info,
21 sk_sp<GrD3DResourceState> state,
22 GrMipMapsStatus mipMapsStatus)
23 : GrSurface(gpu, dimensions, info.fProtected)
24 , GrD3DTextureResource(info, std::move(state))
25 , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus) {
26 SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
27 this->registerWithCache(budgeted);
28 if (GrDxgiFormatIsCompressed(info.fFormat)) {
29 this->setReadOnly();
30 }
31 }
32
GrD3DTexture(GrD3DGpu * gpu,SkISize dimensions,const GrD3DTextureResourceInfo & info,sk_sp<GrD3DResourceState> state,GrMipMapsStatus mipMapsStatus,GrWrapCacheable cacheable,GrIOType ioType)33 GrD3DTexture::GrD3DTexture(GrD3DGpu* gpu, SkISize dimensions, const GrD3DTextureResourceInfo& info,
34 sk_sp<GrD3DResourceState> state, GrMipMapsStatus mipMapsStatus,
35 GrWrapCacheable cacheable, GrIOType ioType)
36 : GrSurface(gpu, dimensions, info.fProtected)
37 , GrD3DTextureResource(info, std::move(state))
38 , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus) {
39 SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
40 if (ioType == kRead_GrIOType) {
41 this->setReadOnly();
42 }
43 this->registerWithCacheWrapped(cacheable);
44 }
45
46 // Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrD3DTexture(GrD3DGpu * gpu,SkISize dimensions,const GrD3DTextureResourceInfo & info,sk_sp<GrD3DResourceState> state,GrMipMapsStatus mipMapsStatus)47 GrD3DTexture::GrD3DTexture(GrD3DGpu* gpu,
48 SkISize dimensions,
49 const GrD3DTextureResourceInfo& info,
50 sk_sp<GrD3DResourceState> state,
51 GrMipMapsStatus mipMapsStatus)
52 : GrSurface(gpu, dimensions, info.fProtected)
53 , GrD3DTextureResource(info, state)
54 , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus) {
55 SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
56 }
57
MakeNewTexture(GrD3DGpu * gpu,SkBudgeted budgeted,SkISize dimensions,const D3D12_RESOURCE_DESC & desc,GrProtected isProtected,GrMipMapsStatus mipMapsStatus)58 sk_sp<GrD3DTexture> GrD3DTexture::MakeNewTexture(GrD3DGpu* gpu, SkBudgeted budgeted,
59 SkISize dimensions,
60 const D3D12_RESOURCE_DESC& desc,
61 GrProtected isProtected,
62 GrMipMapsStatus mipMapsStatus) {
63 GrD3DTextureResourceInfo info;
64 if (!GrD3DTextureResource::InitTextureResourceInfo(gpu, desc, isProtected, &info)) {
65 return nullptr;
66 }
67
68 sk_sp<GrD3DResourceState> state(
69 new GrD3DResourceState(static_cast<D3D12_RESOURCE_STATES>(info.fResourceState)));
70
71 GrD3DTexture* tex = new GrD3DTexture(gpu, budgeted, dimensions, info, std::move(state),
72 mipMapsStatus);
73
74 // The GrD3DTexture takes a ref on the texture so we need to release ours
75 GrD3DTextureResource::ReleaseTextureResourceInfo(&info);
76
77 return sk_sp<GrD3DTexture>(tex);
78 }
79
MakeWrappedTexture(GrD3DGpu * gpu,SkISize dimensions,GrWrapCacheable cacheable,GrIOType ioType,const GrD3DTextureResourceInfo & info,sk_sp<GrD3DResourceState> state)80 sk_sp<GrD3DTexture> GrD3DTexture::MakeWrappedTexture(GrD3DGpu* gpu,
81 SkISize dimensions,
82 GrWrapCacheable cacheable,
83 GrIOType ioType,
84 const GrD3DTextureResourceInfo& info,
85 sk_sp<GrD3DResourceState> state) {
86 // TODO: If a client uses their own heap to allocate, how do we manage that?
87 // Adopted textures require both image and allocation because we're responsible for freeing
88 //SkASSERT(info.fTexture &&
89 // (kBorrow_GrWrapOwnership == wrapOwnership || VK_NULL_HANDLE != info.fAlloc.fMemory));
90
91 GrMipMapsStatus mipMapsStatus = info.fLevelCount > 1 ? GrMipMapsStatus::kValid
92 : GrMipMapsStatus::kNotAllocated;
93
94 return sk_sp<GrD3DTexture>(new GrD3DTexture(gpu, dimensions, info, std::move(state),
95 mipMapsStatus, cacheable, ioType));
96 }
97
onRelease()98 void GrD3DTexture::onRelease() {
99 // We're about to be severed from our GrManagedResource. If there are "finish" idle procs we
100 // have to decide who will handle them. If the resource is still tied to a command buffer we let
101 // it handle them. Otherwise, we handle them.
102 SkASSERT(this->resource());
103 if (this->resource()->isQueuedForWorkOnGpu()) {
104 this->removeFinishIdleProcs();
105 }
106
107 this->releaseResource(this->getD3DGpu());
108
109 INHERITED::onRelease();
110 }
111
onAbandon()112 void GrD3DTexture::onAbandon() {
113 // We're about to be severed from our GrManagedResource. If there are "finish" idle procs we
114 // have to decide who will handle them. If the resource is still tied to a command buffer we let
115 // it handle them. Otherwise, we handle them.
116 SkASSERT(this->resource());
117 if (this->resource()->isQueuedForWorkOnGpu()) {
118 this->removeFinishIdleProcs();
119 }
120
121 this->releaseResource(this->getD3DGpu());
122 INHERITED::onAbandon();
123 }
124
getBackendTexture() const125 GrBackendTexture GrD3DTexture::getBackendTexture() const {
126 return GrBackendTexture(this->width(), this->height(), fInfo, this->grD3DResourceState());
127 }
128
getD3DGpu() const129 GrD3DGpu* GrD3DTexture::getD3DGpu() const {
130 SkASSERT(!this->wasDestroyed());
131 return static_cast<GrD3DGpu*>(this->getGpu());
132 }
133
addIdleProc(sk_sp<GrRefCntedCallback> idleProc,IdleState type)134 void GrD3DTexture::addIdleProc(sk_sp<GrRefCntedCallback> idleProc, IdleState type) {
135 INHERITED::addIdleProc(idleProc, type);
136 if (type == IdleState::kFinished) {
137 if (auto* resource = this->resource()) {
138 resource->addIdleProc(this, std::move(idleProc));
139 }
140 }
141 }
142
callIdleProcsOnBehalfOfResource()143 void GrD3DTexture::callIdleProcsOnBehalfOfResource() {
144 // If we got here then the resource is being removed from its last command buffer and the
145 // texture is idle in the cache. Any kFlush idle procs should already have been called. So
146 // the texture and resource should have the same set of procs.
147 SkASSERT(this->resource());
148 SkASSERT(this->resource()->idleProcCnt() == fIdleProcs.count());
149 #ifdef SK_DEBUG
150 for (int i = 0; i < fIdleProcs.count(); ++i) {
151 SkASSERT(fIdleProcs[i] == this->resource()->idleProc(i));
152 }
153 #endif
154 fIdleProcs.reset();
155 this->resource()->resetIdleProcs();
156 }
157
willRemoveLastRef()158 void GrD3DTexture::willRemoveLastRef() {
159 if (!fIdleProcs.count()) {
160 return;
161 }
162 // This is called when the GrTexture is purgeable. However, we need to check whether the
163 // Resource is still owned by any command buffers. If it is then it will call the proc.
164 auto* resource = this->resource();
165 SkASSERT(resource);
166 if (!resource->isQueuedForWorkOnGpu()) {
167 // Everything must go!
168 fIdleProcs.reset();
169 resource->resetIdleProcs();
170 } else {
171 // The procs that should be called on flush but not finish are those that are owned
172 // by the GrD3DTexture and not the Resource. We do this by copying the resource's array
173 // and thereby dropping refs to procs we own but the resource does not.
174 fIdleProcs.reset(resource->idleProcCnt());
175 for (int i = 0; i < fIdleProcs.count(); ++i) {
176 fIdleProcs[i] = resource->idleProc(i);
177 }
178 }
179 }
180
removeFinishIdleProcs()181 void GrD3DTexture::removeFinishIdleProcs() {
182 // This should only be called by onRelease/onAbandon when we have already checked for a
183 // resource.
184 const auto* resource = this->resource();
185 SkASSERT(resource);
186 SkSTArray<4, sk_sp<GrRefCntedCallback>> procsToKeep;
187 int resourceIdx = 0;
188 // The idle procs that are common between the GrD3DTexture and its Resource should be found in
189 // the same order.
190 for (int i = 0; i < fIdleProcs.count(); ++i) {
191 if (fIdleProcs[i] == resource->idleProc(resourceIdx)) {
192 ++resourceIdx;
193 } else {
194 procsToKeep.push_back(fIdleProcs[i]);
195 }
196 }
197 SkASSERT(resourceIdx == resource->idleProcCnt());
198 fIdleProcs = procsToKeep;
199 }
200