blob: 31d0dd21d3ce92f63d280bc937a0bf48b3fcb5b1 [file] [log] [blame]
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001/*
Jim Van Verth03b8ab22020-02-24 11:36:15 -05002 * Copyright 2020 Google LLC
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05003 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05008#include "src/gpu/d3d/GrD3DGpu.h"
9
Jim Van Verth96bfeff2020-04-09 14:36:12 -040010#include "include/gpu/GrBackendSurface.h"
Jim Van Verth9aa9a682020-04-01 10:13:48 -040011#include "include/gpu/d3d/GrD3DBackendContext.h"
Jim Van Verthc632aa62020-04-17 16:58:20 -040012#include "src/core/SkConvertPixels.h"
Jim Van Verth96bfeff2020-04-09 14:36:12 -040013#include "src/core/SkMipMap.h"
Jim Van Verthc632aa62020-04-17 16:58:20 -040014#include "src/gpu/GrDataUtils.h"
15#include "src/gpu/GrTexturePriv.h"
Jim Van Verthd6ad4802020-04-03 14:59:20 -040016#include "src/gpu/d3d/GrD3DBuffer.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050017#include "src/gpu/d3d/GrD3DCaps.h"
18#include "src/gpu/d3d/GrD3DOpsRenderPass.h"
Jim Van Verth4f51f472020-04-13 11:02:21 -040019#include "src/gpu/d3d/GrD3DStencilAttachment.h"
Jim Van Verthaa90dad2020-03-30 15:00:39 -040020#include "src/gpu/d3d/GrD3DTexture.h"
21#include "src/gpu/d3d/GrD3DTextureRenderTarget.h"
22#include "src/gpu/d3d/GrD3DUtil.h"
Greg Daniel5fc5c812020-04-23 10:30:23 -040023#include "src/sksl/SkSLCompiler.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050024
Jim Van Verth9b5e16c2020-04-20 10:45:52 -040025#if GR_TEST_UTILS
26#include <DXProgrammableCapture.h>
27#endif
28
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050029sk_sp<GrGpu> GrD3DGpu::Make(const GrD3DBackendContext& backendContext,
30 const GrContextOptions& contextOptions, GrContext* context) {
31 return sk_sp<GrGpu>(new GrD3DGpu(context, contextOptions, backendContext));
32}
33
Greg Daniel83ed2132020-03-24 13:15:33 -040034// This constant determines how many OutstandingCommandLists are allocated together as a block in
35// the deque. As such it needs to balance allocating too much memory vs. incurring
36// allocation/deallocation thrashing. It should roughly correspond to the max number of outstanding
37// command lists we expect to see.
38static const int kDefaultOutstandingAllocCnt = 8;
39
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050040GrD3DGpu::GrD3DGpu(GrContext* context, const GrContextOptions& contextOptions,
41 const GrD3DBackendContext& backendContext)
Jim Van Verth03b8ab22020-02-24 11:36:15 -050042 : INHERITED(context)
43 , fDevice(backendContext.fDevice)
Greg Daniel02c45902020-03-09 10:58:09 -040044
45 , fQueue(backendContext.fQueue)
Greg Daniel83ed2132020-03-24 13:15:33 -040046 , fResourceProvider(this)
Greg Daniel5fc5c812020-04-23 10:30:23 -040047 , fOutstandingCommandLists(sizeof(OutstandingCommandList), kDefaultOutstandingAllocCnt)
48 , fCompiler(new SkSL::Compiler()) {
Jim Van Verth8ec13302020-02-26 12:59:56 -050049 fCaps.reset(new GrD3DCaps(contextOptions,
Jim Van Verth9aa9a682020-04-01 10:13:48 -040050 backendContext.fAdapter.get(),
51 backendContext.fDevice.get()));
Greg Daniel85da3362020-03-09 15:18:35 -040052
53 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
Greg Daniele52c9782020-03-23 14:18:37 -040054 SkASSERT(fCurrentDirectCommandList);
Greg Daniel83ed2132020-03-24 13:15:33 -040055
56 SkASSERT(fCurrentFenceValue == 0);
57 SkDEBUGCODE(HRESULT hr = ) fDevice->CreateFence(fCurrentFenceValue, D3D12_FENCE_FLAG_NONE,
58 IID_PPV_ARGS(&fFence));
59 SkASSERT(SUCCEEDED(hr));
Jim Van Verth9b5e16c2020-04-20 10:45:52 -040060
61#if GR_TEST_UTILS
62 HRESULT getAnalysis = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&fGraphicsAnalysis));
63 if (FAILED(getAnalysis)) {
64 fGraphicsAnalysis = nullptr;
65 }
66#endif
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050067}
68
Greg Daniel83ed2132020-03-24 13:15:33 -040069GrD3DGpu::~GrD3DGpu() {
70 this->destroyResources();
71}
72
73void GrD3DGpu::destroyResources() {
74 if (fCurrentDirectCommandList) {
75 fCurrentDirectCommandList->close();
Jim Van Verthba7f2292020-04-21 08:56:47 -040076 fCurrentDirectCommandList->reset();
Greg Daniel83ed2132020-03-24 13:15:33 -040077 }
78
79 // We need to make sure everything has finished on the queue.
Jim Van Verthc632aa62020-04-17 16:58:20 -040080 this->waitForQueueCompletion();
Greg Daniel83ed2132020-03-24 13:15:33 -040081
82 SkDEBUGCODE(uint64_t fenceValue = fFence->GetCompletedValue();)
83
84 // We used a placement new for each object in fOutstandingCommandLists, so we're responsible
85 // for calling the destructor on each of them as well.
86 while (!fOutstandingCommandLists.empty()) {
Jim Van Verthf43da142020-06-09 16:34:43 -040087 OutstandingCommandList* list = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel83ed2132020-03-24 13:15:33 -040088 SkASSERT(list->fFenceValue <= fenceValue);
89 // No reason to recycle the command lists since we are destroying all resources anyways.
90 list->~OutstandingCommandList();
Jim Van Verthf43da142020-06-09 16:34:43 -040091 fOutstandingCommandLists.pop_front();
Greg Daniel83ed2132020-03-24 13:15:33 -040092 }
Jim Van Verthf2788862020-06-03 17:33:12 -040093
94 fResourceProvider.destroyResources();
Greg Daniel83ed2132020-03-24 13:15:33 -040095}
Greg Daniel31a7b072020-02-26 15:31:49 -050096
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050097GrOpsRenderPass* GrD3DGpu::getOpsRenderPass(
Robert Phillips96f22372020-05-20 12:31:18 -040098 GrRenderTarget* rt, GrStencilAttachment*,
99 GrSurfaceOrigin origin, const SkIRect& bounds,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500100 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
Greg Daniel31a7b072020-02-26 15:31:49 -0500101 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500102 const SkTArray<GrSurfaceProxy*, true>& sampledProxies) {
Greg Daniel31a7b072020-02-26 15:31:49 -0500103 if (!fCachedOpsRenderPass) {
104 fCachedOpsRenderPass.reset(new GrD3DOpsRenderPass(this));
105 }
106
107 if (!fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies)) {
108 return nullptr;
109 }
110 return fCachedOpsRenderPass.get();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500111}
112
Jim Van Verthc632aa62020-04-17 16:58:20 -0400113bool GrD3DGpu::submitDirectCommandList(SyncQueue sync) {
Greg Daniel83ed2132020-03-24 13:15:33 -0400114 SkASSERT(fCurrentDirectCommandList);
115
Jim Van Verth3eadce22020-06-01 11:34:49 -0400116 fResourceProvider.prepForSubmit();
117
Jim Van Verthc632aa62020-04-17 16:58:20 -0400118 GrD3DDirectCommandList::SubmitResult result = fCurrentDirectCommandList->submit(fQueue.get());
119 if (result == GrD3DDirectCommandList::SubmitResult::kFailure) {
120 return false;
121 } else if (result == GrD3DDirectCommandList::SubmitResult::kNoWork) {
122 if (sync == SyncQueue::kForce) {
123 this->waitForQueueCompletion();
Jim Van Verth682a2f42020-05-13 16:54:09 -0400124 this->checkForFinishedCommandLists();
Jim Van Verthc632aa62020-04-17 16:58:20 -0400125 }
126 return true;
127 }
Greg Daniel83ed2132020-03-24 13:15:33 -0400128
129 new (fOutstandingCommandLists.push_back()) OutstandingCommandList(
130 std::move(fCurrentDirectCommandList), ++fCurrentFenceValue);
131
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400132 SkDEBUGCODE(HRESULT hr = ) fQueue->Signal(fFence.get(), fCurrentFenceValue);
Greg Daniel83ed2132020-03-24 13:15:33 -0400133 SkASSERT(SUCCEEDED(hr));
134
Jim Van Verthc632aa62020-04-17 16:58:20 -0400135 if (sync == SyncQueue::kForce) {
136 this->waitForQueueCompletion();
137 }
138
Greg Daniel83ed2132020-03-24 13:15:33 -0400139 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
140
141 // This should be done after we have a new command list in case the freeing of any resources
142 // held by a finished command list causes us send a new command to the gpu (like changing the
143 // resource state.
144 this->checkForFinishedCommandLists();
145
146 SkASSERT(fCurrentDirectCommandList);
Jim Van Verthc632aa62020-04-17 16:58:20 -0400147 return true;
Greg Daniel83ed2132020-03-24 13:15:33 -0400148}
149
150void GrD3DGpu::checkForFinishedCommandLists() {
151 uint64_t currentFenceValue = fFence->GetCompletedValue();
152
153 // Iterate over all the outstanding command lists to see if any have finished. The commands
154 // lists are in order from oldest to newest, so we start at the front to check if their fence
155 // value is less than the last signaled value. If so we pop it off and move onto the next.
156 // Repeat till we find a command list that has not finished yet (and all others afterwards are
157 // also guaranteed to not have finished).
158 SkDeque::F2BIter iter(fOutstandingCommandLists);
159 const OutstandingCommandList* curList = (const OutstandingCommandList*)iter.next();
160 while (curList && curList->fFenceValue <= currentFenceValue) {
161 curList = (const OutstandingCommandList*)iter.next();
162 OutstandingCommandList* front = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel7a5f1fa2020-03-24 14:50:19 -0400163 fResourceProvider.recycleDirectCommandList(std::move(front->fCommandList));
Greg Daniel83ed2132020-03-24 13:15:33 -0400164 // Since we used placement new we are responsible for calling the destructor manually.
165 front->~OutstandingCommandList();
166 fOutstandingCommandLists.pop_front();
167 }
168}
169
Jim Van Verthc632aa62020-04-17 16:58:20 -0400170void GrD3DGpu::waitForQueueCompletion() {
171 if (fFence->GetCompletedValue() < fCurrentFenceValue) {
172 HANDLE fenceEvent;
173 fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
174 SkASSERT(fenceEvent);
175 SkDEBUGCODE(HRESULT hr = ) fFence->SetEventOnCompletion(fCurrentFenceValue, fenceEvent);
176 SkASSERT(SUCCEEDED(hr));
177 WaitForSingleObject(fenceEvent, INFINITE);
178 CloseHandle(fenceEvent);
179 }
180}
181
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500182void GrD3DGpu::submit(GrOpsRenderPass* renderPass) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400183 SkASSERT(fCachedOpsRenderPass.get() == renderPass);
184
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500185 // TODO: actually submit something here
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400186 fCachedOpsRenderPass.reset();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500187}
188
Greg Danield4928d02020-06-19 11:13:26 -0400189void GrD3DGpu::addFinishedProc(GrGpuFinishedProc finishedProc,
190 GrGpuFinishedContext finishedContext) {
191 SkASSERT(finishedProc);
192 sk_sp<GrRefCntedCallback> finishedCallback(
193 new GrRefCntedCallback(finishedProc, finishedContext));
194 // Besides the current command list, we also add the finishedCallback to the newest outstanding
195 // command list. Our contract for calling the proc is that all previous submitted command lists
196 // have finished when we call it. However, if our current command list has no work when it is
197 // flushed it will drop its ref to the callback immediately. But the previous work may not have
198 // finished. It is safe to only add the proc to the newest outstanding commandlist cause that
199 // must finish after all previously submitted command lists.
200 OutstandingCommandList* back = (OutstandingCommandList*)fOutstandingCommandLists.back();
201 if (back) {
202 back->fCommandList->addFinishedCallback(finishedCallback);
203 }
204 fCurrentDirectCommandList->addFinishedCallback(std::move(finishedCallback));
205}
206
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500207void GrD3DGpu::querySampleLocations(GrRenderTarget* rt, SkTArray<SkPoint>* sampleLocations) {
208 // TODO
209}
210
211sk_sp<GrTexture> GrD3DGpu::onCreateTexture(SkISize dimensions,
212 const GrBackendFormat& format,
213 GrRenderable renderable,
214 int renderTargetSampleCnt,
215 SkBudgeted budgeted,
216 GrProtected isProtected,
217 int mipLevelCount,
218 uint32_t levelClearMask) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400219 DXGI_FORMAT dxgiFormat;
220 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
221 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
222
223 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
224
225 if (renderable == GrRenderable::kYes) {
226 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
227 }
228
229 // This desc refers to the texture that will be read by the client. Thus even if msaa is
230 // requested, this describes the resolved texture. Therefore we always have samples set
231 // to 1.
232 SkASSERT(mipLevelCount > 0);
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400233 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400234 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
235 // TODO: will use 4MB alignment for MSAA textures and 64KB for everything else
236 // might want to manually set alignment to 4KB for smaller textures
237 resourceDesc.Alignment = 0;
238 resourceDesc.Width = dimensions.fWidth;
239 resourceDesc.Height = dimensions.fHeight;
240 resourceDesc.DepthOrArraySize = 1;
241 resourceDesc.MipLevels = mipLevelCount;
242 resourceDesc.Format = dxgiFormat;
243 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400244 // quality levels are only supported for tiled resources so ignore for now
245 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400246 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400247 resourceDesc.Flags = usageFlags;
248
249 GrMipMapsStatus mipMapsStatus =
250 mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
251
252 sk_sp<GrD3DTexture> tex;
253 if (renderable == GrRenderable::kYes) {
254 tex = GrD3DTextureRenderTarget::MakeNewTextureRenderTarget(
255 this, budgeted, dimensions, renderTargetSampleCnt, resourceDesc, isProtected,
256 mipMapsStatus);
257 } else {
258 tex = GrD3DTexture::MakeNewTexture(this, budgeted, dimensions, resourceDesc, isProtected,
259 mipMapsStatus);
260 }
261
262 if (!tex) {
263 return nullptr;
264 }
265
266 if (levelClearMask) {
267 // TODO
268 }
269 return std::move(tex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500270}
271
272sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
273 const GrBackendFormat& format,
274 SkBudgeted budgeted,
275 GrMipMapped mipMapped,
276 GrProtected isProtected,
277 const void* data, size_t dataSize) {
278 // TODO
279 return nullptr;
280}
281
Jim Van Verth9145f782020-04-28 12:01:12 -0400282static int get_surface_sample_cnt(GrSurface* surf) {
283 if (const GrRenderTarget* rt = surf->asRenderTarget()) {
284 return rt->numSamples();
285 }
286 return 0;
287}
288
289bool GrD3DGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
290 const SkIPoint& dstPoint) {
291
292 if (src->isProtected() && !dst->isProtected()) {
293 SkDebugf("Can't copy from protected memory to non-protected");
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400294 return false;
295 }
Jim Van Verth9145f782020-04-28 12:01:12 -0400296
297 int dstSampleCnt = get_surface_sample_cnt(dst);
298 int srcSampleCnt = get_surface_sample_cnt(src);
299
300 GrD3DTextureResource* dstTexResource;
301 GrD3DTextureResource* srcTexResource;
302 GrRenderTarget* dstRT = dst->asRenderTarget();
303 if (dstRT) {
304 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(dstRT);
305 dstTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
306 } else {
307 SkASSERT(dst->asTexture());
308 dstTexResource = static_cast<GrD3DTexture*>(dst->asTexture());
309 }
310 GrRenderTarget* srcRT = src->asRenderTarget();
311 if (srcRT) {
312 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(srcRT);
313 srcTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
314 } else {
315 SkASSERT(src->asTexture());
316 srcTexResource = static_cast<GrD3DTexture*>(src->asTexture());
317 }
318
319 DXGI_FORMAT dstFormat = dstTexResource->dxgiFormat();
320 DXGI_FORMAT srcFormat = srcTexResource->dxgiFormat();
321
322 if (this->d3dCaps().canCopyAsResolve(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
323 this->copySurfaceAsResolve(dst, src, srcRect, dstPoint);
324 return true;
325 }
326
327 if (this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
328 this->copySurfaceAsCopyTexture(dst, src, dstTexResource, srcTexResource, srcRect, dstPoint);
329 return true;
330 }
331
332 return false;
333}
334
335void GrD3DGpu::copySurfaceAsCopyTexture(GrSurface* dst, GrSurface* src,
336 GrD3DTextureResource* dstResource,
337 GrD3DTextureResource* srcResource,
338 const SkIRect& srcRect, const SkIPoint& dstPoint) {
339#ifdef SK_DEBUG
340 int dstSampleCnt = get_surface_sample_cnt(dst);
341 int srcSampleCnt = get_surface_sample_cnt(src);
342 DXGI_FORMAT dstFormat = dstResource->dxgiFormat();
343 DXGI_FORMAT srcFormat;
344 SkAssertResult(dst->backendFormat().asDxgiFormat(&srcFormat));
345 SkASSERT(this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt));
346#endif
347 if (src->isProtected() && !dst->isProtected()) {
348 SkDebugf("Can't copy from protected memory to non-protected");
349 return;
350 }
351
352 dstResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
353 srcResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
354
355 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
356 dstLocation.pResource = dstResource->d3dResource();
357 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
358 dstLocation.SubresourceIndex = 0;
359
360 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
361 srcLocation.pResource = srcResource->d3dResource();
362 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
363 srcLocation.SubresourceIndex = 0;
364
365 D3D12_BOX srcBox = {};
366 srcBox.left = srcRect.fLeft;
367 srcBox.top = srcRect.fTop;
368 srcBox.right = srcRect.fRight;
369 srcBox.bottom = srcRect.fBottom;
370 srcBox.front = 0;
371 srcBox.back = 1;
372 // TODO: use copyResource if copying full resource and sizes match
373 fCurrentDirectCommandList->copyTextureRegion(dstResource->resource(),
374 &dstLocation,
375 dstPoint.fX, dstPoint.fY,
376 srcResource->resource(),
377 &srcLocation,
378 &srcBox);
379
380 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
381 srcRect.width(), srcRect.height());
382 // The rect is already in device space so we pass in kTopLeft so no flip is done.
383 this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
384}
385
386void GrD3DGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
387 const SkIPoint& dstPoint) {
388 // TODO
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400389}
390
Jim Van Verthba7f2292020-04-21 08:56:47 -0400391bool GrD3DGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
392 GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
393 size_t rowBytes) {
394 SkASSERT(surface);
395
396 if (surfaceColorType != dstColorType) {
397 return false;
398 }
399
400 // Set up src location and box
Jim Van Verthc12aad92020-04-24 16:19:01 -0400401 GrD3DTextureResource* texResource = nullptr;
402 GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(surface->asRenderTarget());
403 if (rt) {
404 texResource = rt;
405 } else {
406 texResource = static_cast<GrD3DTexture*>(surface->asTexture());
407 }
408
409 if (!texResource) {
Jim Van Verthba7f2292020-04-21 08:56:47 -0400410 return false;
411 }
Jim Van Verthc12aad92020-04-24 16:19:01 -0400412
Jim Van Verthba7f2292020-04-21 08:56:47 -0400413 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
Jim Van Verthc12aad92020-04-24 16:19:01 -0400414 srcLocation.pResource = texResource->d3dResource();
Jim Van Verthba7f2292020-04-21 08:56:47 -0400415 SkASSERT(srcLocation.pResource);
416 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
417 srcLocation.SubresourceIndex = 0;
418
419 D3D12_BOX srcBox = {};
420 srcBox.left = left;
421 srcBox.top = top;
422 srcBox.right = left + width;
423 srcBox.bottom = top + height;
424 srcBox.front = 0;
425 srcBox.back = 1;
426
427 // Set up dst location and create transfer buffer
428 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
429 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400430 UINT64 transferTotalBytes;
431 const UINT64 baseOffset = 0;
432 D3D12_RESOURCE_DESC desc = srcLocation.pResource->GetDesc();
433 fDevice->GetCopyableFootprints(&desc, 0, 1, baseOffset, &dstLocation.PlacedFootprint,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400434 nullptr, nullptr, &transferTotalBytes);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400435 SkASSERT(transferTotalBytes);
Jim Van Verthfdd36852020-04-21 16:29:44 -0400436 size_t bpp = GrColorTypeBytesPerPixel(dstColorType);
Jim Van Verthc12aad92020-04-24 16:19:01 -0400437 if (this->d3dCaps().bytesPerPixel(texResource->dxgiFormat()) != bpp) {
Jim Van Verthfdd36852020-04-21 16:29:44 -0400438 return false;
439 }
440 size_t tightRowBytes = bpp * width;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400441
442 // TODO: implement some way of reusing buffers instead of making a new one every time.
443 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(transferTotalBytes,
444 GrGpuBufferType::kXferGpuToCpu,
445 kDynamic_GrAccessPattern);
446 GrD3DBuffer* d3dBuf = static_cast<GrD3DBuffer*>(transferBuffer.get());
447 dstLocation.pResource = d3dBuf->d3dResource();
448
449 // Need to change the resource state to COPY_SOURCE in order to download from it
Jim Van Verthc12aad92020-04-24 16:19:01 -0400450 texResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400451
452 fCurrentDirectCommandList->copyTextureRegion(d3dBuf->resource(), &dstLocation, 0, 0,
Jim Van Verthc12aad92020-04-24 16:19:01 -0400453 texResource->resource(), &srcLocation, &srcBox);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400454 this->submitDirectCommandList(SyncQueue::kForce);
455
456 const void* mappedMemory = transferBuffer->map();
457
458 SkRectMemcpy(buffer, rowBytes, mappedMemory, dstLocation.PlacedFootprint.Footprint.RowPitch,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400459 tightRowBytes, height);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400460
461 transferBuffer->unmap();
462
463 return true;
464}
465
466bool GrD3DGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
467 GrColorType surfaceColorType, GrColorType srcColorType,
468 const GrMipLevel texels[], int mipLevelCount,
469 bool prepForTexSampling) {
470 GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
471 if (!d3dTex) {
472 return false;
473 }
474
475 // Make sure we have at least the base level
476 if (!mipLevelCount || !texels[0].fPixels) {
477 return false;
478 }
479
480 SkASSERT(!GrDxgiFormatIsCompressed(d3dTex->dxgiFormat()));
481 bool success = false;
482
483 // Need to change the resource state to COPY_DEST in order to upload to it
484 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
485
486 SkASSERT(mipLevelCount <= d3dTex->texturePriv().maxMipMapLevel() + 1);
487 success = this->uploadToTexture(d3dTex, left, top, width, height, srcColorType, texels,
488 mipLevelCount);
489
490 if (prepForTexSampling) {
491 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
492 }
493
494 return success;
495}
496
497bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex, int left, int top, int width, int height,
498 GrColorType colorType, const GrMipLevel* texels, int mipLevelCount) {
499 SkASSERT(this->caps()->isFormatTexturable(tex->backendFormat()));
500 // The assumption is either that we have no mipmaps, or that our rect is the entire texture
501 SkASSERT(1 == mipLevelCount ||
502 (0 == left && 0 == top && width == tex->width() && height == tex->height()));
503
504 // We assume that if the texture has mip levels, we either upload to all the levels or just the
505 // first.
506 SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
507
508 if (width == 0 || height == 0) {
509 return false;
510 }
511
512 SkASSERT(this->d3dCaps().surfaceSupportsWritePixels(tex));
513 SkASSERT(this->d3dCaps().areColorTypeAndFormatCompatible(colorType, tex->backendFormat()));
514
515 ID3D12Resource* d3dResource = tex->d3dResource();
516 SkASSERT(d3dResource);
517 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
518 // Either upload only the first miplevel or all miplevels
519 SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
520
521 if (1 == mipLevelCount && !texels[0].fPixels) {
522 return true; // no data to upload
523 }
524
525 for (int i = 0; i < mipLevelCount; ++i) {
526 // We do not allow any gaps in the mip data
527 if (!texels[i].fPixels) {
528 return false;
529 }
530 }
531
532 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400533 UINT64 combinedBufferSize;
534 // We reset the width and height in the description to match our subrectangle size
535 // so we don't end up allocating more space than we need.
536 desc.Width = width;
537 desc.Height = height;
538 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
Jim Van Verthfdd36852020-04-21 16:29:44 -0400539 nullptr, nullptr, &combinedBufferSize);
540 size_t bpp = GrColorTypeBytesPerPixel(colorType);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400541 SkASSERT(combinedBufferSize);
542
543 // TODO: do this until we have slices of buttery buffers
544 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(combinedBufferSize,
545 GrGpuBufferType::kXferCpuToGpu,
546 kDynamic_GrAccessPattern);
547 if (!transferBuffer) {
548 return false;
549 }
550 char* bufferData = (char*)transferBuffer->map();
551
552 int currentWidth = width;
553 int currentHeight = height;
554 int layerHeight = tex->height();
555
556 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
557 if (texels[currentMipLevel].fPixels) {
558 SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
559
Jim Van Verthfdd36852020-04-21 16:29:44 -0400560 const size_t trimRowBytes = currentWidth * bpp;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400561 const size_t srcRowBytes = texels[currentMipLevel].fRowBytes;
562
563 char* dst = bufferData + placedFootprints[currentMipLevel].Offset;
564
565 // copy data into the buffer, skipping any trailing bytes
Jim Van Verthba7f2292020-04-21 08:56:47 -0400566 const char* src = (const char*)texels[currentMipLevel].fPixels;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400567 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
568 src, srcRowBytes, trimRowBytes, currentHeight);
569 }
570 currentWidth = std::max(1, currentWidth / 2);
571 currentHeight = std::max(1, currentHeight / 2);
572 layerHeight = currentHeight;
573 }
574
575 transferBuffer->unmap();
576
577 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get());
578 fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, tex, mipLevelCount,
579 placedFootprints.get(), left, top);
580
581 if (mipLevelCount < (int)desc.MipLevels) {
582 tex->texturePriv().markMipMapsDirty();
583 }
584
585 return true;
586}
587
Jim Van Verth9145f782020-04-28 12:01:12 -0400588static bool check_resource_info(const GrD3DTextureResourceInfo& info) {
589 if (!info.fResource.get()) {
590 return false;
591 }
592 return true;
593}
594
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400595static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
596 if (!caps.isFormatTexturable(info.fFormat)) {
597 return false;
598 }
599 return true;
600}
601
602static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
603 int sampleCnt) {
604 if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
605 return false;
606 }
607 return true;
608}
609
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400610sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
611 GrWrapOwnership,
612 GrWrapCacheable wrapType,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400613 GrIOType ioType) {
614 GrD3DTextureResourceInfo textureInfo;
615 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
616 return nullptr;
617 }
618
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400619 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400620 return nullptr;
621 }
622
623 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
624 return nullptr;
625 }
626
627 // TODO: support protected context
628 if (tex.isProtected()) {
629 return nullptr;
630 }
631
632 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
633 SkASSERT(state);
634 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
635 std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500636}
637
638sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400639 GrWrapOwnership,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500640 GrWrapCacheable wrapType) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400641 GrD3DTextureResourceInfo textureInfo;
642 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
643 return nullptr;
644 }
645
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400646 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400647 return nullptr;
648 }
649
650 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
651 return nullptr;
652 }
653
654 // TODO: support protected context
655 if (tex.isProtected()) {
656 return nullptr;
657 }
658
659 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
660 SkASSERT(state);
661 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, kRead_GrIOType,
662 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500663}
664
665sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
666 int sampleCnt,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500667 GrWrapOwnership ownership,
668 GrWrapCacheable cacheable) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400669 GrD3DTextureResourceInfo textureInfo;
670 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
671 return nullptr;
672 }
673
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400674 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400675 return nullptr;
676 }
677
678 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
679 return nullptr;
680 }
681 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
682 return nullptr;
683 }
684
685 // TODO: support protected context
686 if (tex.isProtected()) {
687 return nullptr;
688 }
689
690 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
691
692 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
693 SkASSERT(state);
694
695 return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
696 sampleCnt, cacheable,
697 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500698}
699
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400700sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400701 // Currently the Direct3D backend does not support wrapping of msaa render targets directly. In
702 // general this is not an issue since swapchain images in D3D are never multisampled. Thus if
703 // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
704 // creating and owning the MSAA images.
705 if (rt.sampleCnt() > 1) {
706 return nullptr;
707 }
708
709 GrD3DTextureResourceInfo info;
710 if (!rt.getD3DTextureResourceInfo(&info)) {
711 return nullptr;
712 }
713
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400714 if (!check_resource_info(info)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400715 return nullptr;
716 }
717
718 if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
719 return nullptr;
720 }
721
722 // TODO: support protected context
723 if (rt.isProtected()) {
724 return nullptr;
725 }
726
727 sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
728
729 sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
730 this, rt.dimensions(), 1, info, std::move(state));
731
732 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
733 SkASSERT(!rt.stencilBits());
734 if (tgt) {
735 SkASSERT(tgt->canAttemptStencilAttachment());
736 }
737
738 return std::move(tgt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500739}
740
741sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400742 int sampleCnt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400743
744 GrD3DTextureResourceInfo textureInfo;
745 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
746 return nullptr;
747 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400748 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400749 return nullptr;
750 }
751
752 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
753 return nullptr;
754 }
755
756 // TODO: support protected context
757 if (tex.isProtected()) {
758 return nullptr;
759 }
760
761 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
762 if (!sampleCnt) {
763 return nullptr;
764 }
765
766 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
767 SkASSERT(state);
768
769 return GrD3DRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt,
770 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500771}
772
773sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
Jim Van Verthd6ad4802020-04-03 14:59:20 -0400774 GrAccessPattern accessPattern, const void* data) {
775 sk_sp<GrD3DBuffer> buffer = GrD3DBuffer::Make(this, sizeInBytes, type, accessPattern);
776 if (data && buffer) {
777 buffer->updateData(data, sizeInBytes);
778 }
779
780 return std::move(buffer);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500781}
782
783GrStencilAttachment* GrD3DGpu::createStencilAttachmentForRenderTarget(
784 const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
Jim Van Verth4f51f472020-04-13 11:02:21 -0400785 SkASSERT(numStencilSamples == rt->numSamples() || this->caps()->mixedSamplesSupport());
786 SkASSERT(width >= rt->width());
787 SkASSERT(height >= rt->height());
788
789 const GrD3DCaps::StencilFormat& sFmt = this->d3dCaps().preferredStencilFormat();
790
791 GrD3DStencilAttachment* stencil(GrD3DStencilAttachment::Make(this,
792 width,
793 height,
794 numStencilSamples,
795 sFmt));
796 fStats.incStencilAttachmentCreates();
797 return stencil;
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500798}
799
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400800bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
801 SkISize dimensions,
802 GrTexturable texturable,
803 GrRenderable renderable,
804 GrMipMapped mipMapped,
805 GrD3DTextureResourceInfo* info,
Greg Daniel16032b32020-05-06 15:31:10 -0400806 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400807 SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400808
809 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
810 return false;
811 }
812
813 if (texturable == GrTexturable::kYes && !this->d3dCaps().isFormatTexturable(dxgiFormat)) {
814 return false;
815 }
816
817 if (renderable == GrRenderable::kYes && !this->d3dCaps().isFormatRenderable(dxgiFormat, 1)) {
818 return false;
819 }
820
821 int numMipLevels = 1;
822 if (mipMapped == GrMipMapped::kYes) {
823 numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
824 }
825
826 // create the texture
827 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
828 if (renderable == GrRenderable::kYes) {
829 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
830 }
831
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400832 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400833 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
Greg Daniel16032b32020-05-06 15:31:10 -0400834 resourceDesc.Alignment = 0; // use default alignment
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400835 resourceDesc.Width = dimensions.fWidth;
836 resourceDesc.Height = dimensions.fHeight;
837 resourceDesc.DepthOrArraySize = 1;
838 resourceDesc.MipLevels = numMipLevels;
839 resourceDesc.Format = dxgiFormat;
840 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400841 // quality levels are only supported for tiled resources so ignore for now
842 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Greg Daniel16032b32020-05-06 15:31:10 -0400843 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400844 resourceDesc.Flags = usageFlags;
845
Jim Van Verth280d4f72020-05-04 10:04:24 -0400846 D3D12_CLEAR_VALUE* clearValuePtr = nullptr;
847 D3D12_CLEAR_VALUE clearValue = {};
848 if (renderable == GrRenderable::kYes) {
849 clearValue.Format = dxgiFormat;
850 // Assume transparent black
851 clearValue.Color[0] = 0;
852 clearValue.Color[1] = 0;
853 clearValue.Color[2] = 0;
854 clearValue.Color[3] = 0;
855 clearValuePtr = &clearValue;
856 }
857
Greg Daniel16032b32020-05-06 15:31:10 -0400858 D3D12_RESOURCE_STATES initialState = (renderable == GrRenderable::kYes)
859 ? D3D12_RESOURCE_STATE_RENDER_TARGET
860 : D3D12_RESOURCE_STATE_COPY_DEST;
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400861 if (!GrD3DTextureResource::InitTextureResourceInfo(this, resourceDesc, initialState,
Jim Van Verth280d4f72020-05-04 10:04:24 -0400862 isProtected, clearValuePtr, info)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400863 SkDebugf("Failed to init texture resource info\n");
864 return false;
865 }
866
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400867 return true;
868}
869
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500870GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400871 const GrBackendFormat& format,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400872 GrRenderable renderable,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400873 GrMipMapped mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400874 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400875 this->handleDirtyContext();
876
877 const GrD3DCaps& caps = this->d3dCaps();
878
879 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
880 return {};
881 }
882
883 DXGI_FORMAT dxgiFormat;
884 if (!format.asDxgiFormat(&dxgiFormat)) {
885 return {};
886 }
887
888 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
889 if (!caps.isFormatTexturable(dxgiFormat)) {
890 return {};
891 }
892
893 GrD3DTextureResourceInfo info;
894 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
895 renderable, mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400896 &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400897 return {};
898 }
899
900 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500901}
902
Greg Daniel16032b32020-05-06 15:31:10 -0400903bool GrD3DGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture,
904 sk_sp<GrRefCntedCallback> finishedCallback,
905 const BackendTextureData* data) {
906 // TODO: handle finishedCallback and data upload
907 return true;
908}
909
Greg Danielc1ad77c2020-05-06 11:40:03 -0400910GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(
911 SkISize dimensions, const GrBackendFormat& format, GrMipMapped mipMapped,
912 GrProtected isProtected, sk_sp<GrRefCntedCallback> finishedCallback,
913 const BackendTextureData* data) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400914 this->handleDirtyContext();
915
916 const GrD3DCaps& caps = this->d3dCaps();
917
918 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
919 return {};
920 }
921
922 DXGI_FORMAT dxgiFormat;
923 if (!format.asDxgiFormat(&dxgiFormat)) {
924 return {};
925 }
926
927 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
928 if (!caps.isFormatTexturable(dxgiFormat)) {
929 return {};
930 }
931
932 GrD3DTextureResourceInfo info;
933 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
934 GrRenderable::kNo, mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400935 &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400936 return {};
937 }
938
939 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500940}
941
942void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400943 SkASSERT(GrBackendApi::kDirect3D == tex.fBackend);
944 // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500945}
946
Robert Phillips979b2232020-02-20 10:47:29 -0500947bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
948 return false;
949}
950
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500951#if GR_TEST_UTILS
952bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400953 SkASSERT(GrBackendApi::kDirect3D == tex.backend());
954
955 GrD3DTextureResourceInfo info;
956 if (!tex.getD3DTextureResourceInfo(&info)) {
957 return false;
958 }
959 ID3D12Resource* textureResource = info.fResource.get();
960 if (!textureResource) {
961 return false;
962 }
963 return !(textureResource->GetDesc().Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500964}
965
966GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(int w, int h,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400967 GrColorType colorType) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400968 this->handleDirtyContext();
969
970 if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400971 return {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400972 }
973
974 DXGI_FORMAT dxgiFormat = this->d3dCaps().getFormatFromColorType(colorType);
975
976 GrD3DTextureResourceInfo info;
977 if (!this->createTextureResourceForBackendSurface(dxgiFormat, { w, h }, GrTexturable::kNo,
978 GrRenderable::kYes, GrMipMapped::kNo,
Greg Daniel16032b32020-05-06 15:31:10 -0400979 &info, GrProtected::kNo)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400980 return {};
981 }
982
983 return GrBackendRenderTarget(w, h, 1, info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500984}
985
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400986void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
987 SkASSERT(GrBackendApi::kDirect3D == rt.backend());
988
989 GrD3DTextureResourceInfo info;
990 if (rt.getD3DTextureResourceInfo(&info)) {
991 this->testingOnly_flushGpuAndSync();
992 // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
993 // is deleted.
994 }
995}
996
997void GrD3DGpu::testingOnly_flushGpuAndSync() {
Jim Van Verthc632aa62020-04-17 16:58:20 -0400998 SkAssertResult(this->submitDirectCommandList(SyncQueue::kForce));
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400999}
Jim Van Verthc632aa62020-04-17 16:58:20 -04001000
Jim Van Verth9b5e16c2020-04-20 10:45:52 -04001001void GrD3DGpu::testingOnly_startCapture() {
1002 if (fGraphicsAnalysis) {
1003 fGraphicsAnalysis->BeginCapture();
1004 }
1005}
1006
1007void GrD3DGpu::testingOnly_endCapture() {
1008 if (fGraphicsAnalysis) {
1009 fGraphicsAnalysis->EndCapture();
1010 }
1011}
1012#endif
1013
Jim Van Verthc632aa62020-04-17 16:58:20 -04001014///////////////////////////////////////////////////////////////////////////////
1015
Greg Daniela5a6b322020-04-23 12:52:27 -04001016void GrD3DGpu::addResourceBarriers(sk_sp<GrManagedResource> resource,
Jim Van Verthc632aa62020-04-17 16:58:20 -04001017 int numBarriers,
1018 D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
1019 SkASSERT(fCurrentDirectCommandList);
1020 SkASSERT(resource);
1021
Greg Daniela5a6b322020-04-23 12:52:27 -04001022 fCurrentDirectCommandList->resourceBarrier(std::move(resource), numBarriers, barriers);
Jim Van Verthc632aa62020-04-17 16:58:20 -04001023}
1024
Greg Daniel9efe3862020-06-11 11:51:06 -04001025void GrD3DGpu::prepareSurfacesForBackendAccessAndStateUpdates(
1026 GrSurfaceProxy* proxies[],
1027 int numProxies,
1028 SkSurface::BackendSurfaceAccess access,
1029 const GrBackendSurfaceMutableState* newState) {
Jim Van Verth682a2f42020-05-13 16:54:09 -04001030 SkASSERT(numProxies >= 0);
1031 SkASSERT(!numProxies || proxies);
1032
1033 // prepare proxies by transitioning to PRESENT renderState
1034 if (numProxies && access == SkSurface::BackendSurfaceAccess::kPresent) {
1035 GrD3DTextureResource* resource;
1036 for (int i = 0; i < numProxies; ++i) {
1037 SkASSERT(proxies[i]->isInstantiated());
1038 if (GrTexture* tex = proxies[i]->peekTexture()) {
1039 resource = static_cast<GrD3DTexture*>(tex);
1040 } else {
1041 GrRenderTarget* rt = proxies[i]->peekRenderTarget();
1042 SkASSERT(rt);
1043 resource = static_cast<GrD3DRenderTarget*>(rt);
1044 }
1045 resource->prepareForPresent(this);
1046 }
1047 }
1048}
1049
Jim Van Verthc632aa62020-04-17 16:58:20 -04001050bool GrD3DGpu::onSubmitToGpu(bool syncCpu) {
1051 if (syncCpu) {
1052 return this->submitDirectCommandList(SyncQueue::kForce);
1053 } else {
1054 return this->submitDirectCommandList(SyncQueue::kSkip);
1055 }
1056}