• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/GrD3DGpu.h"
9 
10 #include "include/gpu/GrBackendSurface.h"
11 #include "include/gpu/d3d/GrD3DBackendContext.h"
12 #include "src/core/SkConvertPixels.h"
13 #include "src/core/SkMipmap.h"
14 #include "src/gpu/GrBackendUtils.h"
15 #include "src/gpu/GrDataUtils.h"
16 #include "src/gpu/GrTexture.h"
17 #include "src/gpu/GrThreadSafePipelineBuilder.h"
18 #include "src/gpu/d3d/GrD3DAMDMemoryAllocator.h"
19 #include "src/gpu/d3d/GrD3DAttachment.h"
20 #include "src/gpu/d3d/GrD3DBuffer.h"
21 #include "src/gpu/d3d/GrD3DCaps.h"
22 #include "src/gpu/d3d/GrD3DOpsRenderPass.h"
23 #include "src/gpu/d3d/GrD3DSemaphore.h"
24 #include "src/gpu/d3d/GrD3DTexture.h"
25 #include "src/gpu/d3d/GrD3DTextureRenderTarget.h"
26 #include "src/gpu/d3d/GrD3DUtil.h"
27 #include "src/sksl/SkSLCompiler.h"
28 
29 #if GR_TEST_UTILS
30 #include <DXProgrammableCapture.h>
31 #endif
32 
pipelineBuilder()33 GrThreadSafePipelineBuilder* GrD3DGpu::pipelineBuilder() {
34     return nullptr;
35 }
36 
refPipelineBuilder()37 sk_sp<GrThreadSafePipelineBuilder> GrD3DGpu::refPipelineBuilder() {
38     return nullptr;
39 }
40 
41 
Make(const GrD3DBackendContext & backendContext,const GrContextOptions & contextOptions,GrDirectContext * direct)42 sk_sp<GrGpu> GrD3DGpu::Make(const GrD3DBackendContext& backendContext,
43                             const GrContextOptions& contextOptions, GrDirectContext* direct) {
44     sk_sp<GrD3DMemoryAllocator> memoryAllocator = backendContext.fMemoryAllocator;
45     if (!memoryAllocator) {
46         // We were not given a memory allocator at creation
47         memoryAllocator = GrD3DAMDMemoryAllocator::Make(
48                 backendContext.fAdapter.get(), backendContext.fDevice.get());
49     }
50     if (!memoryAllocator) {
51         SkDEBUGFAIL("No supplied Direct3D memory allocator and unable to create one internally.");
52         return nullptr;
53     }
54 
55     return sk_sp<GrGpu>(new GrD3DGpu(direct, contextOptions, backendContext, memoryAllocator));
56 }
57 
58 // This constant determines how many OutstandingCommandLists are allocated together as a block in
59 // the deque. As such it needs to balance allocating too much memory vs. incurring
60 // allocation/deallocation thrashing. It should roughly correspond to the max number of outstanding
61 // command lists we expect to see.
62 static const int kDefaultOutstandingAllocCnt = 8;
63 
64 // constants have to be aligned to 256
65 constexpr int kConstantAlignment = 256;
66 
GrD3DGpu(GrDirectContext * direct,const GrContextOptions & contextOptions,const GrD3DBackendContext & backendContext,sk_sp<GrD3DMemoryAllocator> allocator)67 GrD3DGpu::GrD3DGpu(GrDirectContext* direct, const GrContextOptions& contextOptions,
68                    const GrD3DBackendContext& backendContext,
69                    sk_sp<GrD3DMemoryAllocator> allocator)
70         : INHERITED(direct)
71         , fDevice(backendContext.fDevice)
72         , fQueue(backendContext.fQueue)
73         , fMemoryAllocator(std::move(allocator))
74         , fResourceProvider(this)
75         , fStagingBufferManager(this)
76         , fConstantsRingBuffer(this, 128 * 1024, kConstantAlignment, GrGpuBufferType::kVertex)
77         , fOutstandingCommandLists(sizeof(OutstandingCommandList), kDefaultOutstandingAllocCnt) {
78     this->initCapsAndCompiler(sk_make_sp<GrD3DCaps>(contextOptions,
79                                                     backendContext.fAdapter.get(),
80                                                     backendContext.fDevice.get()));
81 
82     fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
83     SkASSERT(fCurrentDirectCommandList);
84 
85     SkASSERT(fCurrentFenceValue == 0);
86     GR_D3D_CALL_ERRCHECK(fDevice->CreateFence(fCurrentFenceValue, D3D12_FENCE_FLAG_NONE,
87                                               IID_PPV_ARGS(&fFence)));
88 
89 #if GR_TEST_UTILS
90     HRESULT getAnalysis = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&fGraphicsAnalysis));
91     if (FAILED(getAnalysis)) {
92         fGraphicsAnalysis = nullptr;
93     }
94 #endif
95 }
96 
~GrD3DGpu()97 GrD3DGpu::~GrD3DGpu() {
98     this->destroyResources();
99 }
100 
destroyResources()101 void GrD3DGpu::destroyResources() {
102     if (fCurrentDirectCommandList) {
103         fCurrentDirectCommandList->close();
104         fCurrentDirectCommandList->reset();
105     }
106 
107     // We need to make sure everything has finished on the queue.
108     this->waitForQueueCompletion();
109 
110     SkDEBUGCODE(uint64_t fenceValue = fFence->GetCompletedValue();)
111 
112     // We used a placement new for each object in fOutstandingCommandLists, so we're responsible
113     // for calling the destructor on each of them as well.
114     while (!fOutstandingCommandLists.empty()) {
115         OutstandingCommandList* list = (OutstandingCommandList*)fOutstandingCommandLists.front();
116         SkASSERT(list->fFenceValue <= fenceValue);
117         // No reason to recycle the command lists since we are destroying all resources anyways.
118         list->~OutstandingCommandList();
119         fOutstandingCommandLists.pop_front();
120     }
121 
122     fStagingBufferManager.reset();
123 
124     fResourceProvider.destroyResources();
125 }
126 
onGetOpsRenderPass(GrRenderTarget * rt,bool,GrAttachment *,GrSurfaceOrigin origin,const SkIRect & bounds,const GrOpsRenderPass::LoadAndStoreInfo & colorInfo,const GrOpsRenderPass::StencilLoadAndStoreInfo & stencilInfo,const SkTArray<GrSurfaceProxy *,true> & sampledProxies,GrXferBarrierFlags renderPassXferBarriers)127 GrOpsRenderPass* GrD3DGpu::onGetOpsRenderPass(
128         GrRenderTarget* rt,
129         bool /*useMSAASurface*/,
130         GrAttachment*,
131         GrSurfaceOrigin origin,
132         const SkIRect& bounds,
133         const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
134         const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
135         const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
136         GrXferBarrierFlags renderPassXferBarriers) {
137     if (!fCachedOpsRenderPass) {
138         fCachedOpsRenderPass.reset(new GrD3DOpsRenderPass(this));
139     }
140 
141     if (!fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies)) {
142         return nullptr;
143     }
144     return fCachedOpsRenderPass.get();
145 }
146 
submitDirectCommandList(SyncQueue sync)147 bool GrD3DGpu::submitDirectCommandList(SyncQueue sync) {
148     SkASSERT(fCurrentDirectCommandList);
149 
150     fResourceProvider.prepForSubmit();
151     for (int i = 0; i < fMipmapCPUDescriptors.count(); ++i) {
152         fResourceProvider.recycleShaderView(fMipmapCPUDescriptors[i]);
153     }
154     fMipmapCPUDescriptors.reset();
155 
156     GrD3DDirectCommandList::SubmitResult result = fCurrentDirectCommandList->submit(fQueue.get());
157     if (result == GrD3DDirectCommandList::SubmitResult::kFailure) {
158         fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
159         return false;
160     } else if (result == GrD3DDirectCommandList::SubmitResult::kNoWork) {
161         if (sync == SyncQueue::kForce) {
162             this->waitForQueueCompletion();
163             this->checkForFinishedCommandLists();
164         }
165         return true;
166     }
167 
168     // We just submitted the command list so make sure all GrD3DPipelineState's mark their cached
169     // uniform data as dirty.
170     fResourceProvider.markPipelineStateUniformsDirty();
171 
172     GrFence fence = this->insertFence();
173     new (fOutstandingCommandLists.push_back()) OutstandingCommandList(
174             std::move(fCurrentDirectCommandList), fence);
175 
176     if (sync == SyncQueue::kForce) {
177         this->waitForQueueCompletion();
178     }
179 
180     fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
181 
182     // This should be done after we have a new command list in case the freeing of any resources
183     // held by a finished command list causes us send a new command to the gpu (like changing the
184     // resource state.
185     this->checkForFinishedCommandLists();
186 
187     SkASSERT(fCurrentDirectCommandList);
188     return true;
189 }
190 
checkForFinishedCommandLists()191 void GrD3DGpu::checkForFinishedCommandLists() {
192     uint64_t currentFenceValue = fFence->GetCompletedValue();
193 
194     // Iterate over all the outstanding command lists to see if any have finished. The commands
195     // lists are in order from oldest to newest, so we start at the front to check if their fence
196     // value is less than the last signaled value. If so we pop it off and move onto the next.
197     // Repeat till we find a command list that has not finished yet (and all others afterwards are
198     // also guaranteed to not have finished).
199     OutstandingCommandList* front = (OutstandingCommandList*)fOutstandingCommandLists.front();
200     while (front && front->fFenceValue <= currentFenceValue) {
201         std::unique_ptr<GrD3DDirectCommandList> currList(std::move(front->fCommandList));
202         // Since we used placement new we are responsible for calling the destructor manually.
203         front->~OutstandingCommandList();
204         fOutstandingCommandLists.pop_front();
205         fResourceProvider.recycleDirectCommandList(std::move(currList));
206         front = (OutstandingCommandList*)fOutstandingCommandLists.front();
207     }
208 }
209 
waitForQueueCompletion()210 void GrD3DGpu::waitForQueueCompletion() {
211     if (fFence->GetCompletedValue() < fCurrentFenceValue) {
212         HANDLE fenceEvent;
213         fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
214         SkASSERT(fenceEvent);
215         GR_D3D_CALL_ERRCHECK(fFence->SetEventOnCompletion(fCurrentFenceValue, fenceEvent));
216         WaitForSingleObject(fenceEvent, INFINITE);
217         CloseHandle(fenceEvent);
218     }
219 }
220 
submit(GrOpsRenderPass * renderPass)221 void GrD3DGpu::submit(GrOpsRenderPass* renderPass) {
222     SkASSERT(fCachedOpsRenderPass.get() == renderPass);
223 
224     fCachedOpsRenderPass->submit();
225     fCachedOpsRenderPass.reset();
226 }
227 
endRenderPass(GrRenderTarget * target,GrSurfaceOrigin origin,const SkIRect & bounds)228 void GrD3DGpu::endRenderPass(GrRenderTarget* target, GrSurfaceOrigin origin,
229                              const SkIRect& bounds) {
230     this->didWriteToSurface(target, origin, &bounds);
231 }
232 
addFinishedProc(GrGpuFinishedProc finishedProc,GrGpuFinishedContext finishedContext)233 void GrD3DGpu::addFinishedProc(GrGpuFinishedProc finishedProc,
234                                GrGpuFinishedContext finishedContext) {
235     SkASSERT(finishedProc);
236     this->addFinishedCallback(GrRefCntedCallback::Make(finishedProc, finishedContext));
237 }
238 
addFinishedCallback(sk_sp<GrRefCntedCallback> finishedCallback)239 void GrD3DGpu::addFinishedCallback(sk_sp<GrRefCntedCallback> finishedCallback) {
240     SkASSERT(finishedCallback);
241     // Besides the current command list, we also add the finishedCallback to the newest outstanding
242     // command list. Our contract for calling the proc is that all previous submitted command lists
243     // have finished when we call it. However, if our current command list has no work when it is
244     // flushed it will drop its ref to the callback immediately. But the previous work may not have
245     // finished. It is safe to only add the proc to the newest outstanding commandlist cause that
246     // must finish after all previously submitted command lists.
247     OutstandingCommandList* back = (OutstandingCommandList*)fOutstandingCommandLists.back();
248     if (back) {
249         back->fCommandList->addFinishedCallback(finishedCallback);
250     }
251     fCurrentDirectCommandList->addFinishedCallback(std::move(finishedCallback));
252 }
253 
createD3DTexture(SkISize dimensions,DXGI_FORMAT dxgiFormat,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrProtected isProtected,int mipLevelCount,GrMipmapStatus mipmapStatus)254 sk_sp<GrD3DTexture> GrD3DGpu::createD3DTexture(SkISize dimensions,
255                                                DXGI_FORMAT dxgiFormat,
256                                                GrRenderable renderable,
257                                                int renderTargetSampleCnt,
258                                                SkBudgeted budgeted,
259                                                GrProtected isProtected,
260                                                int mipLevelCount,
261                                                GrMipmapStatus mipmapStatus) {
262     D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
263     if (renderable == GrRenderable::kYes) {
264         usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
265     }
266 
267     // This desc refers to a texture that will be read by the client. Thus even if msaa is
268     // requested, this describes the resolved texture. Therefore we always have samples set
269     // to 1.
270     SkASSERT(mipLevelCount > 0);
271     D3D12_RESOURCE_DESC resourceDesc = {};
272     resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
273     // TODO: will use 4MB alignment for MSAA textures and 64KB for everything else
274     //       might want to manually set alignment to 4KB for smaller textures
275     resourceDesc.Alignment = 0;
276     resourceDesc.Width = dimensions.fWidth;
277     resourceDesc.Height = dimensions.fHeight;
278     resourceDesc.DepthOrArraySize = 1;
279     resourceDesc.MipLevels = mipLevelCount;
280     resourceDesc.Format = dxgiFormat;
281     resourceDesc.SampleDesc.Count = 1;
282     resourceDesc.SampleDesc.Quality = DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;
283     resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;  // use driver-selected swizzle
284     resourceDesc.Flags = usageFlags;
285 
286     if (renderable == GrRenderable::kYes) {
287         return GrD3DTextureRenderTarget::MakeNewTextureRenderTarget(
288                 this, budgeted, dimensions, renderTargetSampleCnt, resourceDesc, isProtected,
289                 mipmapStatus);
290     } else {
291         return GrD3DTexture::MakeNewTexture(this, budgeted, dimensions, resourceDesc, isProtected,
292                                             mipmapStatus);
293     }
294 }
295 
onCreateTexture(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrProtected isProtected,int mipLevelCount,uint32_t levelClearMask)296 sk_sp<GrTexture> GrD3DGpu::onCreateTexture(SkISize dimensions,
297                                            const GrBackendFormat& format,
298                                            GrRenderable renderable,
299                                            int renderTargetSampleCnt,
300                                            SkBudgeted budgeted,
301                                            GrProtected isProtected,
302                                            int mipLevelCount,
303                                            uint32_t levelClearMask) {
304     DXGI_FORMAT dxgiFormat;
305     SkAssertResult(format.asDxgiFormat(&dxgiFormat));
306     SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
307 
308     GrMipmapStatus mipmapStatus = mipLevelCount > 1 ? GrMipmapStatus::kDirty
309                                                     : GrMipmapStatus::kNotAllocated;
310 
311     sk_sp<GrD3DTexture> tex = this->createD3DTexture(dimensions, dxgiFormat, renderable,
312                                                      renderTargetSampleCnt, budgeted, isProtected,
313                                                      mipLevelCount, mipmapStatus);
314     if (!tex) {
315         return nullptr;
316     }
317 
318     if (levelClearMask) {
319         // TODO
320     }
321 
322     return std::move(tex);
323 }
324 
copy_compressed_data(char * mapPtr,DXGI_FORMAT dxgiFormat,D3D12_PLACED_SUBRESOURCE_FOOTPRINT * placedFootprints,UINT * numRows,UINT64 * rowSizeInBytes,const void * compressedData,int numMipLevels)325 static void copy_compressed_data(char* mapPtr, DXGI_FORMAT dxgiFormat,
326                                  D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints,
327                                  UINT* numRows, UINT64* rowSizeInBytes,
328                                  const void* compressedData, int numMipLevels) {
329     SkASSERT(compressedData && numMipLevels);
330     SkASSERT(GrDxgiFormatIsCompressed(dxgiFormat));
331     SkASSERT(mapPtr);
332 
333     const char* src = static_cast<const char*>(compressedData);
334     for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) {
335         // copy data into the buffer, skipping any trailing bytes
336         char* dst = mapPtr + placedFootprints[currentMipLevel].Offset;
337         SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
338                      src, rowSizeInBytes[currentMipLevel], rowSizeInBytes[currentMipLevel],
339                      numRows[currentMipLevel]);
340         src += numRows[currentMipLevel] * rowSizeInBytes[currentMipLevel];
341     }
342 }
343 
onCreateCompressedTexture(SkISize dimensions,const GrBackendFormat & format,SkBudgeted budgeted,GrMipmapped mipMapped,GrProtected isProtected,const void * data,size_t dataSize)344 sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
345                                                      const GrBackendFormat& format,
346                                                      SkBudgeted budgeted,
347                                                      GrMipmapped mipMapped,
348                                                      GrProtected isProtected,
349                                                      const void* data, size_t dataSize) {
350     DXGI_FORMAT dxgiFormat;
351     SkAssertResult(format.asDxgiFormat(&dxgiFormat));
352     SkASSERT(GrDxgiFormatIsCompressed(dxgiFormat));
353 
354     SkDEBUGCODE(SkImage::CompressionType compression = GrBackendFormatToCompressionType(format));
355     SkASSERT(dataSize == SkCompressedFormatDataSize(compression, dimensions,
356                                                     mipMapped == GrMipmapped::kYes));
357 
358     int mipLevelCount = 1;
359     if (mipMapped == GrMipmapped::kYes) {
360         mipLevelCount = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
361     }
362     GrMipmapStatus mipmapStatus = mipLevelCount > 1 ? GrMipmapStatus::kValid
363                                                     : GrMipmapStatus::kNotAllocated;
364 
365     sk_sp<GrD3DTexture> d3dTex = this->createD3DTexture(dimensions, dxgiFormat, GrRenderable::kNo,
366                                                      1, budgeted, isProtected,
367                                                      mipLevelCount, mipmapStatus);
368     if (!d3dTex) {
369         return nullptr;
370     }
371 
372     ID3D12Resource* d3dResource = d3dTex->d3dResource();
373     SkASSERT(d3dResource);
374     D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
375     // Either upload only the first miplevel or all miplevels
376     SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
377 
378     SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
379     SkAutoTMalloc<UINT> numRows(mipLevelCount);
380     SkAutoTMalloc<UINT64> rowSizeInBytes(mipLevelCount);
381     UINT64 combinedBufferSize;
382     // We reset the width and height in the description to match our subrectangle size
383     // so we don't end up allocating more space than we need.
384     desc.Width = dimensions.width();
385     desc.Height = dimensions.height();
386     fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
387                                    numRows.get(), rowSizeInBytes.get(), &combinedBufferSize);
388     SkASSERT(combinedBufferSize);
389 
390     GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
391             combinedBufferSize, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
392     if (!slice.fBuffer) {
393         return nullptr;
394     }
395 
396     char* bufferData = (char*)slice.fOffsetMapPtr;
397 
398     copy_compressed_data(bufferData, desc.Format, placedFootprints.get(), numRows.get(),
399                          rowSizeInBytes.get(), data, mipLevelCount);
400 
401     // Update the offsets in the footprints to be relative to the slice's offset
402     for (int i = 0; i < mipLevelCount; ++i) {
403         placedFootprints[i].Offset += slice.fOffset;
404     }
405 
406     ID3D12Resource* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer)->d3dResource();
407     fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, d3dTex.get(), mipLevelCount,
408                                                    placedFootprints.get(), 0, 0);
409 
410     return std::move(d3dTex);
411 }
412 
onCreateCompressedTexture(SkISize dimensions,const GrBackendFormat & format,SkBudgeted budgeted,GrMipmapped mipMapped,GrProtected isProtected,OH_NativeBuffer * nativeBuffer,size_t bufferSize)413 sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
414                                                 const GrBackendFormat& format,
415                                                 SkBudgeted budgeted,
416                                                 GrMipmapped mipMapped,
417                                                 GrProtected isProtected,
418                                                 OH_NativeBuffer* nativeBuffer,
419                                                 size_t bufferSize) {
420     SkASSERT(!"unimplemented");
421     return nullptr;
422 }
423 
get_surface_sample_cnt(GrSurface * surf)424 static int get_surface_sample_cnt(GrSurface* surf) {
425     if (const GrRenderTarget* rt = surf->asRenderTarget()) {
426         return rt->numSamples();
427     }
428     return 0;
429 }
430 
onCopySurface(GrSurface * dst,GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint)431 bool GrD3DGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
432                    const SkIPoint& dstPoint) {
433 
434     if (src->isProtected() && !dst->isProtected()) {
435         SkDebugf("Can't copy from protected memory to non-protected");
436         return false;
437     }
438 
439     int dstSampleCnt = get_surface_sample_cnt(dst);
440     int srcSampleCnt = get_surface_sample_cnt(src);
441 
442     GrD3DTextureResource* dstTexResource;
443     GrD3DTextureResource* srcTexResource;
444     GrRenderTarget* dstRT = dst->asRenderTarget();
445     if (dstRT) {
446         GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(dstRT);
447         dstTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
448     } else {
449         SkASSERT(dst->asTexture());
450         dstTexResource = static_cast<GrD3DTexture*>(dst->asTexture());
451     }
452     GrRenderTarget* srcRT = src->asRenderTarget();
453     if (srcRT) {
454         GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(srcRT);
455         srcTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
456     } else {
457         SkASSERT(src->asTexture());
458         srcTexResource = static_cast<GrD3DTexture*>(src->asTexture());
459     }
460 
461     DXGI_FORMAT dstFormat = dstTexResource->dxgiFormat();
462     DXGI_FORMAT srcFormat = srcTexResource->dxgiFormat();
463 
464     if (this->d3dCaps().canCopyAsResolve(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
465         this->copySurfaceAsResolve(dst, src, srcRect, dstPoint);
466         return true;
467     }
468 
469     if (this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
470         this->copySurfaceAsCopyTexture(dst, src, dstTexResource, srcTexResource, srcRect, dstPoint);
471         return true;
472     }
473 
474     return false;
475 }
476 
copySurfaceAsCopyTexture(GrSurface * dst,GrSurface * src,GrD3DTextureResource * dstResource,GrD3DTextureResource * srcResource,const SkIRect & srcRect,const SkIPoint & dstPoint)477 void GrD3DGpu::copySurfaceAsCopyTexture(GrSurface* dst, GrSurface* src,
478                                         GrD3DTextureResource* dstResource,
479                                         GrD3DTextureResource* srcResource,
480                                         const SkIRect& srcRect, const SkIPoint& dstPoint) {
481 #ifdef SK_DEBUG
482     int dstSampleCnt = get_surface_sample_cnt(dst);
483     int srcSampleCnt = get_surface_sample_cnt(src);
484     DXGI_FORMAT dstFormat = dstResource->dxgiFormat();
485     DXGI_FORMAT srcFormat;
486     SkAssertResult(dst->backendFormat().asDxgiFormat(&srcFormat));
487     SkASSERT(this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt));
488 #endif
489     if (src->isProtected() && !dst->isProtected()) {
490         SkDebugf("Can't copy from protected memory to non-protected");
491         return;
492     }
493 
494     dstResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
495     srcResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
496 
497     D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
498     dstLocation.pResource = dstResource->d3dResource();
499     dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
500     dstLocation.SubresourceIndex = 0;
501 
502     D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
503     srcLocation.pResource = srcResource->d3dResource();
504     srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
505     srcLocation.SubresourceIndex = 0;
506 
507     D3D12_BOX srcBox = {};
508     srcBox.left = srcRect.fLeft;
509     srcBox.top = srcRect.fTop;
510     srcBox.right = srcRect.fRight;
511     srcBox.bottom = srcRect.fBottom;
512     srcBox.front = 0;
513     srcBox.back = 1;
514     // TODO: use copyResource if copying full resource and sizes match
515     fCurrentDirectCommandList->copyTextureRegionToTexture(dstResource->resource(),
516                                                           &dstLocation,
517                                                           dstPoint.fX, dstPoint.fY,
518                                                           srcResource->resource(),
519                                                           &srcLocation,
520                                                           &srcBox);
521 
522     SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
523                                         srcRect.width(), srcRect.height());
524     // The rect is already in device space so we pass in kTopLeft so no flip is done.
525     this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
526 }
527 
copySurfaceAsResolve(GrSurface * dst,GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint)528 void GrD3DGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
529                                     const SkIPoint& dstPoint) {
530     GrD3DRenderTarget* srcRT = static_cast<GrD3DRenderTarget*>(src->asRenderTarget());
531     SkASSERT(srcRT);
532 
533     this->resolveTexture(dst, dstPoint.fX, dstPoint.fY, srcRT, srcRect);
534     SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
535                                         srcRect.width(), srcRect.height());
536     // The rect is already in device space so we pass in kTopLeft so no flip is done.
537     this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
538 }
539 
resolveTexture(GrSurface * dst,int32_t dstX,int32_t dstY,GrD3DRenderTarget * src,const SkIRect & srcIRect)540 void GrD3DGpu::resolveTexture(GrSurface* dst, int32_t dstX, int32_t dstY,
541                               GrD3DRenderTarget* src, const SkIRect& srcIRect) {
542     SkASSERT(dst);
543     SkASSERT(src && src->numSamples() > 1 && src->msaaTextureResource());
544 
545     D3D12_RECT srcRect = { srcIRect.fLeft, srcIRect.fTop, srcIRect.fRight, srcIRect.fBottom };
546 
547     GrD3DTextureResource* dstTextureResource;
548     GrRenderTarget* dstRT = dst->asRenderTarget();
549     if (dstRT) {
550         dstTextureResource = static_cast<GrD3DRenderTarget*>(dstRT);
551     } else {
552         SkASSERT(dst->asTexture());
553         dstTextureResource = static_cast<GrD3DTexture*>(dst->asTexture());
554     }
555 
556     dstTextureResource->setResourceState(this, D3D12_RESOURCE_STATE_RESOLVE_DEST);
557     src->msaaTextureResource()->setResourceState(this, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
558 
559     fCurrentDirectCommandList->resolveSubresourceRegion(dstTextureResource, dstX, dstY,
560                                                         src->msaaTextureResource(), &srcRect);
561 }
562 
onResolveRenderTarget(GrRenderTarget * target,const SkIRect & resolveRect)563 void GrD3DGpu::onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect) {
564     SkASSERT(target->numSamples() > 1);
565     GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(target);
566     SkASSERT(rt->msaaTextureResource() && rt != rt->msaaTextureResource());
567 
568     this->resolveTexture(target, resolveRect.fLeft, resolveRect.fTop, rt, resolveRect);
569 }
570 
onReadPixels(GrSurface * surface,SkIRect rect,GrColorType surfaceColorType,GrColorType dstColorType,void * buffer,size_t rowBytes)571 bool GrD3DGpu::onReadPixels(GrSurface* surface,
572                             SkIRect rect,
573                             GrColorType surfaceColorType,
574                             GrColorType dstColorType,
575                             void* buffer,
576                             size_t rowBytes) {
577     SkASSERT(surface);
578 
579     if (surfaceColorType != dstColorType) {
580         return false;
581     }
582 
583     GrD3DTextureResource* texResource = nullptr;
584     GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(surface->asRenderTarget());
585     if (rt) {
586         texResource = rt;
587     } else {
588         texResource = static_cast<GrD3DTexture*>(surface->asTexture());
589     }
590 
591     if (!texResource) {
592         return false;
593     }
594 
595     D3D12_RESOURCE_DESC desc = texResource->d3dResource()->GetDesc();
596     D3D12_PLACED_SUBRESOURCE_FOOTPRINT placedFootprint;
597     UINT64 transferTotalBytes;
598     fDevice->GetCopyableFootprints(&desc, 0, 1, 0, &placedFootprint,
599                                    nullptr, nullptr, &transferTotalBytes);
600     SkASSERT(transferTotalBytes);
601     // TODO: implement some way of reusing buffers instead of making a new one every time.
602     sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(transferTotalBytes,
603                                                            GrGpuBufferType::kXferGpuToCpu,
604                                                            kDynamic_GrAccessPattern);
605 
606     this->readOrTransferPixels(texResource, rect, transferBuffer, placedFootprint);
607     this->submitDirectCommandList(SyncQueue::kForce);
608 
609     // Copy back to CPU buffer
610     size_t bpp = GrColorTypeBytesPerPixel(dstColorType);
611     if (GrDxgiFormatBytesPerBlock(texResource->dxgiFormat()) != bpp) {
612         return false;
613     }
614     size_t tightRowBytes = bpp * rect.width();
615 
616     const void* mappedMemory = transferBuffer->map();
617 
618     SkRectMemcpy(buffer,
619                  rowBytes,
620                  mappedMemory,
621                  placedFootprint.Footprint.RowPitch,
622                  tightRowBytes,
623                  rect.height());
624 
625     transferBuffer->unmap();
626 
627     return true;
628 }
629 
readOrTransferPixels(GrD3DTextureResource * texResource,SkIRect rect,sk_sp<GrGpuBuffer> transferBuffer,const D3D12_PLACED_SUBRESOURCE_FOOTPRINT & placedFootprint)630 void GrD3DGpu::readOrTransferPixels(GrD3DTextureResource* texResource,
631                                     SkIRect rect,
632                                     sk_sp<GrGpuBuffer> transferBuffer,
633                                     const D3D12_PLACED_SUBRESOURCE_FOOTPRINT& placedFootprint) {
634     // Set up src location and box
635     D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
636     srcLocation.pResource = texResource->d3dResource();
637     SkASSERT(srcLocation.pResource);
638     srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
639     srcLocation.SubresourceIndex = 0;
640 
641     D3D12_BOX srcBox = {};
642     srcBox.left = rect.left();
643     srcBox.top = rect.top();
644     srcBox.right = rect.right();
645     srcBox.bottom = rect.bottom();
646     srcBox.front = 0;
647     srcBox.back = 1;
648 
649     // Set up dst location
650     D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
651     dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
652     dstLocation.PlacedFootprint = placedFootprint;
653     GrD3DBuffer* d3dBuf = static_cast<GrD3DBuffer*>(transferBuffer.get());
654     dstLocation.pResource = d3dBuf->d3dResource();
655 
656     // Need to change the resource state to COPY_SOURCE in order to download from it
657     texResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
658 
659     fCurrentDirectCommandList->copyTextureRegionToBuffer(transferBuffer, &dstLocation, 0, 0,
660                                                          texResource->resource(), &srcLocation,
661                                                          &srcBox);
662 }
663 
onWritePixels(GrSurface * surface,SkIRect rect,GrColorType surfaceColorType,GrColorType srcColorType,const GrMipLevel texels[],int mipLevelCount,bool prepForTexSampling)664 bool GrD3DGpu::onWritePixels(GrSurface* surface,
665                              SkIRect rect,
666                              GrColorType surfaceColorType,
667                              GrColorType srcColorType,
668                              const GrMipLevel texels[],
669                              int mipLevelCount,
670                              bool prepForTexSampling) {
671     GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
672     if (!d3dTex) {
673         return false;
674     }
675 
676     // Make sure we have at least the base level
677     if (!mipLevelCount || !texels[0].fPixels) {
678         return false;
679     }
680 
681     SkASSERT(!GrDxgiFormatIsCompressed(d3dTex->dxgiFormat()));
682     bool success = false;
683 
684     // Need to change the resource state to COPY_DEST in order to upload to it
685     d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
686 
687     SkASSERT(mipLevelCount <= d3dTex->maxMipmapLevel() + 1);
688     success = this->uploadToTexture(d3dTex, rect, srcColorType, texels, mipLevelCount);
689 
690     if (prepForTexSampling) {
691         d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
692     }
693 
694     return success;
695 }
696 
uploadToTexture(GrD3DTexture * tex,SkIRect rect,GrColorType colorType,const GrMipLevel * texels,int mipLevelCount)697 bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex,
698                                SkIRect rect,
699                                GrColorType colorType,
700                                const GrMipLevel* texels,
701                                int mipLevelCount) {
702     SkASSERT(this->d3dCaps().isFormatTexturable(tex->dxgiFormat()));
703     // The assumption is either that we have no mipmaps, or that our rect is the entire texture
704     SkASSERT(mipLevelCount == 1 || rect == SkIRect::MakeSize(tex->dimensions()));
705 
706     // We assume that if the texture has mip levels, we either upload to all the levels or just the
707     // first.
708     SkASSERT(mipLevelCount == 1 || mipLevelCount == (tex->maxMipmapLevel() + 1));
709 
710     if (rect.isEmpty()) {
711         return false;
712     }
713 
714     SkASSERT(this->d3dCaps().surfaceSupportsWritePixels(tex));
715     SkASSERT(this->d3dCaps().areColorTypeAndFormatCompatible(colorType, tex->backendFormat()));
716 
717     ID3D12Resource* d3dResource = tex->d3dResource();
718     SkASSERT(d3dResource);
719     D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
720     // Either upload only the first miplevel or all miplevels
721     SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
722 
723     if (1 == mipLevelCount && !texels[0].fPixels) {
724         return true;   // no data to upload
725     }
726 
727     for (int i = 0; i < mipLevelCount; ++i) {
728         // We do not allow any gaps in the mip data
729         if (!texels[i].fPixels) {
730             return false;
731         }
732     }
733 
734     SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
735     UINT64 combinedBufferSize;
736     // We reset the width and height in the description to match our subrectangle size
737     // so we don't end up allocating more space than we need.
738     desc.Width = rect.width();
739     desc.Height = rect.height();
740     fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
741                                    nullptr, nullptr, &combinedBufferSize);
742     size_t bpp = GrColorTypeBytesPerPixel(colorType);
743     SkASSERT(combinedBufferSize);
744 
745     GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
746             combinedBufferSize, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
747     if (!slice.fBuffer) {
748         return false;
749     }
750 
751     char* bufferData = (char*)slice.fOffsetMapPtr;
752 
753     int currentWidth = rect.width();
754     int currentHeight = rect.height();
755     for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
756         if (texels[currentMipLevel].fPixels) {
757 
758             const size_t trimRowBytes = currentWidth * bpp;
759             const size_t srcRowBytes = texels[currentMipLevel].fRowBytes;
760 
761             char* dst = bufferData + placedFootprints[currentMipLevel].Offset;
762 
763             // copy data into the buffer, skipping any trailing bytes
764             const char* src = (const char*)texels[currentMipLevel].fPixels;
765             SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
766                          src, srcRowBytes, trimRowBytes, currentHeight);
767         }
768         currentWidth = std::max(1, currentWidth / 2);
769         currentHeight = std::max(1, currentHeight / 2);
770     }
771 
772     // Update the offsets in the footprints to be relative to the slice's offset
773     for (int i = 0; i < mipLevelCount; ++i) {
774         placedFootprints[i].Offset += slice.fOffset;
775     }
776 
777     ID3D12Resource* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer)->d3dResource();
778     fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer,
779                                                    tex,
780                                                    mipLevelCount,
781                                                    placedFootprints.get(),
782                                                    rect.left(),
783                                                    rect.top());
784 
785     if (mipLevelCount < (int)desc.MipLevels) {
786         tex->markMipmapsDirty();
787     }
788 
789     return true;
790 }
791 
onTransferPixelsTo(GrTexture * texture,SkIRect rect,GrColorType surfaceColorType,GrColorType bufferColorType,sk_sp<GrGpuBuffer> transferBuffer,size_t bufferOffset,size_t rowBytes)792 bool GrD3DGpu::onTransferPixelsTo(GrTexture* texture,
793                                   SkIRect rect,
794                                   GrColorType surfaceColorType,
795                                   GrColorType bufferColorType,
796                                   sk_sp<GrGpuBuffer> transferBuffer,
797                                   size_t bufferOffset,
798                                   size_t rowBytes) {
799     if (!this->currentCommandList()) {
800         return false;
801     }
802 
803     if (!transferBuffer) {
804         return false;
805     }
806 
807     size_t bpp = GrColorTypeBytesPerPixel(bufferColorType);
808     if (GrBackendFormatBytesPerPixel(texture->backendFormat()) != bpp) {
809         return false;
810     }
811 
812     // D3D requires offsets for texture transfers to be aligned to this value
813     if (SkToBool(bufferOffset & (D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT-1))) {
814         return false;
815     }
816 
817     GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(texture);
818     if (!d3dTex) {
819         return false;
820     }
821 
822     SkDEBUGCODE(DXGI_FORMAT format = d3dTex->dxgiFormat());
823 
824     // Can't transfer compressed data
825     SkASSERT(!GrDxgiFormatIsCompressed(format));
826 
827     SkASSERT(GrDxgiFormatBytesPerBlock(format) == GrColorTypeBytesPerPixel(bufferColorType));
828 
829     SkASSERT(SkIRect::MakeSize(texture->dimensions()).contains(rect));
830 
831     // Set up copy region
832     D3D12_PLACED_SUBRESOURCE_FOOTPRINT placedFootprint = {};
833     ID3D12Resource* d3dResource = d3dTex->d3dResource();
834     SkASSERT(d3dResource);
835     D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
836     desc.Width = rect.width();
837     desc.Height = rect.height();
838     UINT64 totalBytes;
839     fDevice->GetCopyableFootprints(&desc, 0, 1, 0, &placedFootprint,
840                                    nullptr, nullptr, &totalBytes);
841     placedFootprint.Offset = bufferOffset;
842 
843     // Change state of our target so it can be copied to
844     d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
845 
846     // Copy the buffer to the image.
847     ID3D12Resource* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get())->d3dResource();
848     fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer,
849                                                    d3dTex,
850                                                    1,
851                                                    &placedFootprint,
852                                                    rect.left(),
853                                                    rect.top());
854     this->currentCommandList()->addGrBuffer(std::move(transferBuffer));
855 
856     d3dTex->markMipmapsDirty();
857     return true;
858 }
859 
onTransferPixelsFrom(GrSurface * surface,SkIRect rect,GrColorType surfaceColorType,GrColorType bufferColorType,sk_sp<GrGpuBuffer> transferBuffer,size_t offset)860 bool GrD3DGpu::onTransferPixelsFrom(GrSurface* surface,
861                                     SkIRect rect,
862                                     GrColorType surfaceColorType,
863                                     GrColorType bufferColorType,
864                                     sk_sp<GrGpuBuffer> transferBuffer,
865                                     size_t offset) {
866     if (!this->currentCommandList()) {
867         return false;
868     }
869     SkASSERT(surface);
870     SkASSERT(transferBuffer);
871     // TODO
872     //if (fProtectedContext == GrProtected::kYes) {
873     //    return false;
874     //}
875 
876     // D3D requires offsets for texture transfers to be aligned to this value
877     if (SkToBool(offset & (D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT-1))) {
878         return false;
879     }
880 
881     GrD3DTextureResource* texResource = nullptr;
882     GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(surface->asRenderTarget());
883     if (rt) {
884         texResource = rt;
885     } else {
886         texResource = static_cast<GrD3DTexture*>(surface->asTexture());
887     }
888 
889     if (!texResource) {
890         return false;
891     }
892 
893     SkDEBUGCODE(DXGI_FORMAT format = texResource->dxgiFormat());
894     SkASSERT(GrDxgiFormatBytesPerBlock(format) == GrColorTypeBytesPerPixel(bufferColorType));
895 
896     D3D12_RESOURCE_DESC desc = texResource->d3dResource()->GetDesc();
897     desc.Width = rect.width();
898     desc.Height = rect.height();
899     D3D12_PLACED_SUBRESOURCE_FOOTPRINT placedFootprint;
900     UINT64 transferTotalBytes;
901     fDevice->GetCopyableFootprints(&desc, 0, 1, offset, &placedFootprint,
902                                    nullptr, nullptr, &transferTotalBytes);
903     SkASSERT(transferTotalBytes);
904 
905     this->readOrTransferPixels(texResource, rect, transferBuffer, placedFootprint);
906 
907     // TODO: It's not clear how to ensure the transfer is done before we read from the buffer,
908     // other than maybe doing a resource state transition.
909 
910     return true;
911 }
912 
check_resource_info(const GrD3DTextureResourceInfo & info)913 static bool check_resource_info(const GrD3DTextureResourceInfo& info) {
914     if (!info.fResource.get()) {
915         return false;
916     }
917     return true;
918 }
919 
check_tex_resource_info(const GrD3DCaps & caps,const GrD3DTextureResourceInfo & info)920 static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
921     if (!caps.isFormatTexturable(info.fFormat)) {
922         return false;
923     }
924     // We don't support sampling from multisampled textures.
925     if (info.fSampleCount != 1) {
926         return false;
927     }
928     return true;
929 }
930 
check_rt_resource_info(const GrD3DCaps & caps,const GrD3DTextureResourceInfo & info,int sampleCnt)931 static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
932                                 int sampleCnt) {
933     if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
934         return false;
935     }
936     return true;
937 }
938 
onWrapBackendTexture(const GrBackendTexture & tex,GrWrapOwnership,GrWrapCacheable wrapType,GrIOType ioType)939 sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
940                                                 GrWrapOwnership,
941                                                 GrWrapCacheable wrapType,
942                                                 GrIOType ioType) {
943     GrD3DTextureResourceInfo textureInfo;
944     if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
945         return nullptr;
946     }
947 
948     if (!check_resource_info(textureInfo)) {
949         return nullptr;
950     }
951 
952     if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
953         return nullptr;
954     }
955 
956     // TODO: support protected context
957     if (tex.isProtected()) {
958         return nullptr;
959     }
960 
961     sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
962     SkASSERT(state);
963     return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
964                                             std::move(state));
965 }
966 
onWrapCompressedBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership,GrWrapCacheable wrapType)967 sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
968                                                           GrWrapOwnership ownership,
969                                                           GrWrapCacheable wrapType) {
970     return this->onWrapBackendTexture(tex, ownership, wrapType, kRead_GrIOType);
971 }
972 
onWrapRenderableBackendTexture(const GrBackendTexture & tex,int sampleCnt,GrWrapOwnership ownership,GrWrapCacheable cacheable)973 sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
974                                                           int sampleCnt,
975                                                           GrWrapOwnership ownership,
976                                                           GrWrapCacheable cacheable) {
977     GrD3DTextureResourceInfo textureInfo;
978     if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
979         return nullptr;
980     }
981 
982     if (!check_resource_info(textureInfo)) {
983         return nullptr;
984     }
985 
986     if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
987         return nullptr;
988     }
989     if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
990         return nullptr;
991     }
992 
993     // TODO: support protected context
994     if (tex.isProtected()) {
995         return nullptr;
996     }
997 
998     sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
999 
1000     sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
1001     SkASSERT(state);
1002 
1003     return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
1004                                                                     sampleCnt, cacheable,
1005                                                                     textureInfo, std::move(state));
1006 }
1007 
onWrapBackendRenderTarget(const GrBackendRenderTarget & rt)1008 sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
1009     GrD3DTextureResourceInfo info;
1010     if (!rt.getD3DTextureResourceInfo(&info)) {
1011         return nullptr;
1012     }
1013 
1014     if (!check_resource_info(info)) {
1015         return nullptr;
1016     }
1017 
1018     if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
1019         return nullptr;
1020     }
1021 
1022     // TODO: support protected context
1023     if (rt.isProtected()) {
1024         return nullptr;
1025     }
1026 
1027     sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
1028 
1029     sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
1030             this, rt.dimensions(), rt.sampleCnt(), info, std::move(state));
1031 
1032     // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
1033     SkASSERT(!rt.stencilBits());
1034     if (tgt) {
1035         SkASSERT(tgt->canAttemptStencilAttachment(tgt->numSamples() > 1));
1036     }
1037 
1038     return std::move(tgt);
1039 }
1040 
is_odd(int x)1041 static bool is_odd(int x) {
1042     return x > 1 && SkToBool(x & 0x1);
1043 }
1044 
1045 // TODO: enable when sRGB shader supported
1046 //static bool is_srgb(DXGI_FORMAT format) {
1047 //    // the only one we support at the moment
1048 //    return (format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB);
1049 //}
1050 
is_bgra(DXGI_FORMAT format)1051 static bool is_bgra(DXGI_FORMAT format) {
1052     // the only one we support at the moment
1053     return (format == DXGI_FORMAT_B8G8R8A8_UNORM);
1054 }
1055 
onRegenerateMipMapLevels(GrTexture * tex)1056 bool GrD3DGpu::onRegenerateMipMapLevels(GrTexture * tex) {
1057     auto * d3dTex = static_cast<GrD3DTexture*>(tex);
1058     SkASSERT(tex->textureType() == GrTextureType::k2D);
1059     int width = tex->width();
1060     int height = tex->height();
1061 
1062     // determine if we can read from and mipmap this format
1063     const GrD3DCaps & caps = this->d3dCaps();
1064     if (!caps.isFormatTexturable(d3dTex->dxgiFormat()) ||
1065         !caps.mipmapSupport()) {
1066         return false;
1067     }
1068 
1069     sk_sp<GrD3DTexture> uavTexture;
1070     sk_sp<GrD3DTexture> bgraAliasTexture;
1071     DXGI_FORMAT originalFormat = d3dTex->dxgiFormat();
1072     D3D12_RESOURCE_DESC originalDesc = d3dTex->d3dResource()->GetDesc();
1073     // if the format is unordered accessible and resource flag is set, use resource for uav
1074     if (caps.isFormatUnorderedAccessible(originalFormat) &&
1075         (originalDesc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) {
1076         uavTexture = sk_ref_sp(d3dTex);
1077     } else {
1078         // need to make a copy and use that for our uav
1079         D3D12_RESOURCE_DESC uavDesc = originalDesc;
1080         uavDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
1081         // if the format is unordered accessible, copy to resource with same format and flag set
1082         if (!caps.isFormatUnorderedAccessible(originalFormat)) {
1083             // for the BGRA and sRGB cases, we find a suitable RGBA format to use instead
1084             if (is_bgra(originalFormat)) {
1085                 uavDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1086                 // Technically if this support is not available we should not be doing
1087                 // aliasing. However, on Intel the BGRA and RGBA swizzle appears to be
1088                 // the same so it still works. We may need to disable BGRA support
1089                 // on a case-by-base basis if this doesn't hold true in general.
1090                 if (caps.standardSwizzleLayoutSupport()) {
1091                     uavDesc.Layout = D3D12_TEXTURE_LAYOUT_64KB_STANDARD_SWIZZLE;
1092                 }
1093             // TODO: enable when sRGB shader supported
1094             //} else if (is_srgb(originalFormat)) {
1095             //    uavDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1096             } else {
1097                 return false;
1098             }
1099         }
1100         // TODO: make this a scratch texture
1101         GrProtected grProtected = tex->isProtected() ? GrProtected::kYes : GrProtected::kNo;
1102         uavTexture = GrD3DTexture::MakeNewTexture(this, SkBudgeted::kNo, tex->dimensions(),
1103                                                   uavDesc, grProtected, GrMipmapStatus::kDirty);
1104         if (!uavTexture) {
1105             return false;
1106         }
1107 
1108         d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
1109         if (!caps.isFormatUnorderedAccessible(originalFormat) && is_bgra(originalFormat)) {
1110             // for BGRA, we alias this uavTexture with a BGRA texture and copy to that
1111             bgraAliasTexture = GrD3DTexture::MakeAliasingTexture(this, uavTexture, originalDesc,
1112                                                                  D3D12_RESOURCE_STATE_COPY_DEST);
1113             // make the BGRA version the active alias
1114             this->currentCommandList()->aliasingBarrier(nullptr,
1115                                                         nullptr,
1116                                                         bgraAliasTexture->resource(),
1117                                                         bgraAliasTexture->d3dResource());
1118             // copy top miplevel to bgraAliasTexture (should already be in COPY_DEST state)
1119             this->currentCommandList()->copyTextureToTexture(bgraAliasTexture.get(), d3dTex, 0);
1120             // make the RGBA version the active alias
1121             this->currentCommandList()->aliasingBarrier(bgraAliasTexture->resource(),
1122                                                         bgraAliasTexture->d3dResource(),
1123                                                         uavTexture->resource(),
1124                                                         uavTexture->d3dResource());
1125         } else {
1126             // copy top miplevel to uavTexture
1127             uavTexture->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
1128             this->currentCommandList()->copyTextureToTexture(uavTexture.get(), d3dTex, 0);
1129         }
1130     }
1131 
1132     uint32_t levelCount = d3dTex->mipLevels();
1133     // SkMipmap doesn't include the base level in the level count so we have to add 1
1134     SkASSERT((int)levelCount == SkMipmap::ComputeLevelCount(tex->width(), tex->height()) + 1);
1135 
1136     sk_sp<GrD3DRootSignature> rootSig = fResourceProvider.findOrCreateRootSignature(1, 1);
1137     this->currentCommandList()->setComputeRootSignature(rootSig);
1138 
1139     // TODO: use linear vs. srgb shader based on texture format
1140     sk_sp<GrD3DPipeline> pipeline = this->resourceProvider().findOrCreateMipmapPipeline();
1141     SkASSERT(pipeline);
1142     this->currentCommandList()->setPipelineState(std::move(pipeline));
1143 
1144     // set sampler
1145     GrSamplerState samplerState(SkFilterMode::kLinear, SkMipmapMode::kNearest);
1146     std::vector<D3D12_CPU_DESCRIPTOR_HANDLE> samplers(1);
1147     samplers[0] = fResourceProvider.findOrCreateCompatibleSampler(samplerState);
1148     this->currentCommandList()->addSampledTextureRef(uavTexture.get());
1149     sk_sp<GrD3DDescriptorTable> samplerTable = fResourceProvider.findOrCreateSamplerTable(samplers);
1150 
1151     // Transition the top subresource to be readable in the compute shader
1152     D3D12_RESOURCE_STATES currentResourceState = uavTexture->currentState();
1153     D3D12_RESOURCE_TRANSITION_BARRIER barrier;
1154     barrier.pResource = uavTexture->d3dResource();
1155     barrier.Subresource = 0;
1156     barrier.StateBefore = currentResourceState;
1157     barrier.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1158     this->addResourceBarriers(uavTexture->resource(), 1, &barrier);
1159 
1160     // Generate the miplevels
1161     for (unsigned int dstMip = 1; dstMip < levelCount; ++dstMip) {
1162         unsigned int srcMip = dstMip - 1;
1163         width = std::max(1, width / 2);
1164         height = std::max(1, height / 2);
1165 
1166         unsigned int sampleMode = 0;
1167         if (is_odd(width) && is_odd(height)) {
1168             sampleMode = 1;
1169         } else if (is_odd(width)) {
1170             sampleMode = 2;
1171         } else if (is_odd(height)) {
1172             sampleMode = 3;
1173         }
1174 
1175         // set constants
1176         struct {
1177             SkSize inverseSize;
1178             uint32_t mipLevel;
1179             uint32_t sampleMode;
1180         } constantData = { {1.f / width, 1.f / height}, srcMip, sampleMode };
1181 
1182         D3D12_GPU_VIRTUAL_ADDRESS constantsAddress =
1183             fResourceProvider.uploadConstantData(&constantData, sizeof(constantData));
1184         this->currentCommandList()->setComputeRootConstantBufferView(
1185                 (unsigned int)GrD3DRootSignature::ParamIndex::kConstantBufferView,
1186                 constantsAddress);
1187 
1188         std::vector<D3D12_CPU_DESCRIPTOR_HANDLE> shaderViews;
1189         // create SRV
1190         GrD3DDescriptorHeap::CPUHandle srvHandle =
1191                 fResourceProvider.createShaderResourceView(uavTexture->d3dResource(), srcMip, 1);
1192         shaderViews.push_back(srvHandle.fHandle);
1193         fMipmapCPUDescriptors.push_back(srvHandle);
1194         // create UAV
1195         GrD3DDescriptorHeap::CPUHandle uavHandle =
1196                 fResourceProvider.createUnorderedAccessView(uavTexture->d3dResource(), dstMip);
1197         shaderViews.push_back(uavHandle.fHandle);
1198         fMipmapCPUDescriptors.push_back(uavHandle);
1199 
1200         // set up shaderView descriptor table
1201         sk_sp<GrD3DDescriptorTable> srvTable =
1202                 fResourceProvider.findOrCreateShaderViewTable(shaderViews);
1203 
1204         // bind both descriptor tables
1205         this->currentCommandList()->setDescriptorHeaps(srvTable->heap(), samplerTable->heap());
1206         this->currentCommandList()->setComputeRootDescriptorTable(
1207                 (unsigned int)GrD3DRootSignature::ParamIndex::kShaderViewDescriptorTable,
1208                 srvTable->baseGpuDescriptor());
1209         this->currentCommandList()->setComputeRootDescriptorTable(
1210                 static_cast<unsigned int>(GrD3DRootSignature::ParamIndex::kSamplerDescriptorTable),
1211                 samplerTable->baseGpuDescriptor());
1212 
1213         // Transition resource state of dstMip subresource so we can write to it
1214         barrier.Subresource = dstMip;
1215         barrier.StateBefore = currentResourceState;
1216         barrier.StateAfter = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
1217         this->addResourceBarriers(uavTexture->resource(), 1, &barrier);
1218 
1219         // Using the form (x+7)/8 ensures that the remainder is covered as well
1220         this->currentCommandList()->dispatch((width+7)/8, (height+7)/8);
1221 
1222         // guarantee UAV writes have completed
1223         this->currentCommandList()->uavBarrier(uavTexture->resource(), uavTexture->d3dResource());
1224 
1225         // Transition resource state of dstMip subresource so we can read it in the next stage
1226         barrier.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
1227         barrier.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1228         this->addResourceBarriers(uavTexture->resource(), 1, &barrier);
1229     }
1230 
1231     // copy back if necessary
1232     if (uavTexture.get() != d3dTex) {
1233         d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
1234         if (bgraAliasTexture) {
1235             // make the BGRA version the active alias
1236             this->currentCommandList()->aliasingBarrier(uavTexture->resource(),
1237                                                         uavTexture->d3dResource(),
1238                                                         bgraAliasTexture->resource(),
1239                                                         bgraAliasTexture->d3dResource());
1240             // copy from bgraAliasTexture to d3dTex
1241             bgraAliasTexture->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
1242             this->currentCommandList()->copyTextureToTexture(d3dTex, bgraAliasTexture.get());
1243         } else {
1244             barrier.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
1245             barrier.StateBefore = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1246             barrier.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
1247             this->addResourceBarriers(uavTexture->resource(), 1, &barrier);
1248             this->currentCommandList()->copyTextureToTexture(d3dTex, uavTexture.get());
1249         }
1250     } else {
1251         // For simplicity our resource state tracking considers all subresources to have the same
1252         // state. However, we've changed that state one subresource at a time without going through
1253         // the tracking system, so we need to patch up the resource states back to the original.
1254         barrier.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
1255         barrier.StateBefore = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1256         barrier.StateAfter = currentResourceState;
1257         this->addResourceBarriers(d3dTex->resource(), 1, &barrier);
1258     }
1259 
1260     return true;
1261 }
1262 
onCreateBuffer(size_t sizeInBytes,GrGpuBufferType type,GrAccessPattern accessPattern,const void * data)1263 sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
1264                                              GrAccessPattern accessPattern, const void* data) {
1265     sk_sp<GrD3DBuffer> buffer = GrD3DBuffer::Make(this, sizeInBytes, type, accessPattern);
1266     if (data && buffer) {
1267         buffer->updateData(data, sizeInBytes);
1268     }
1269 
1270     return std::move(buffer);
1271 }
1272 
makeStencilAttachment(const GrBackendFormat &,SkISize dimensions,int numStencilSamples)1273 sk_sp<GrAttachment> GrD3DGpu::makeStencilAttachment(const GrBackendFormat& /*colorFormat*/,
1274                                                     SkISize dimensions, int numStencilSamples) {
1275     DXGI_FORMAT sFmt = this->d3dCaps().preferredStencilFormat();
1276 
1277     fStats.incStencilAttachmentCreates();
1278     return GrD3DAttachment::MakeStencil(this, dimensions, numStencilSamples, sFmt);
1279 }
1280 
createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,SkISize dimensions,GrTexturable texturable,GrRenderable renderable,GrMipmapped mipMapped,int sampleCnt,GrD3DTextureResourceInfo * info,GrProtected isProtected)1281 bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
1282                                                       SkISize dimensions,
1283                                                       GrTexturable texturable,
1284                                                       GrRenderable renderable,
1285                                                       GrMipmapped mipMapped,
1286                                                       int sampleCnt,
1287                                                       GrD3DTextureResourceInfo* info,
1288                                                       GrProtected isProtected) {
1289     SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
1290 
1291     if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
1292         return false;
1293     }
1294 
1295     if (texturable == GrTexturable::kYes && !this->d3dCaps().isFormatTexturable(dxgiFormat)) {
1296         return false;
1297     }
1298 
1299     if (renderable == GrRenderable::kYes && !this->d3dCaps().isFormatRenderable(dxgiFormat, 1)) {
1300         return false;
1301     }
1302 
1303     int numMipLevels = 1;
1304     if (mipMapped == GrMipmapped::kYes) {
1305         numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
1306     }
1307 
1308     // create the texture
1309     D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
1310     if (renderable == GrRenderable::kYes) {
1311         usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
1312     }
1313 
1314     D3D12_RESOURCE_DESC resourceDesc = {};
1315     resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
1316     resourceDesc.Alignment = 0;  // use default alignment
1317     resourceDesc.Width = dimensions.fWidth;
1318     resourceDesc.Height = dimensions.fHeight;
1319     resourceDesc.DepthOrArraySize = 1;
1320     resourceDesc.MipLevels = numMipLevels;
1321     resourceDesc.Format = dxgiFormat;
1322     resourceDesc.SampleDesc.Count = sampleCnt;
1323     resourceDesc.SampleDesc.Quality = DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;
1324     resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;  // use driver-selected swizzle
1325     resourceDesc.Flags = usageFlags;
1326 
1327     D3D12_CLEAR_VALUE* clearValuePtr = nullptr;
1328     D3D12_CLEAR_VALUE clearValue = {};
1329     if (renderable == GrRenderable::kYes) {
1330         clearValue.Format = dxgiFormat;
1331         // Assume transparent black
1332         clearValue.Color[0] = 0;
1333         clearValue.Color[1] = 0;
1334         clearValue.Color[2] = 0;
1335         clearValue.Color[3] = 0;
1336         clearValuePtr = &clearValue;
1337     }
1338 
1339     D3D12_RESOURCE_STATES initialState = (renderable == GrRenderable::kYes)
1340                                                  ? D3D12_RESOURCE_STATE_RENDER_TARGET
1341                                                  : D3D12_RESOURCE_STATE_COPY_DEST;
1342     if (!GrD3DTextureResource::InitTextureResourceInfo(this, resourceDesc, initialState,
1343                                                        isProtected, clearValuePtr, info)) {
1344         SkDebugf("Failed to init texture resource info\n");
1345         return false;
1346     }
1347 
1348     return true;
1349 }
1350 
onCreateBackendTexture(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,GrMipmapped mipMapped,GrProtected isProtected)1351 GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
1352                                                   const GrBackendFormat& format,
1353                                                   GrRenderable renderable,
1354                                                   GrMipmapped mipMapped,
1355                                                   GrProtected isProtected) {
1356     const GrD3DCaps& caps = this->d3dCaps();
1357 
1358     if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
1359         return {};
1360     }
1361 
1362     DXGI_FORMAT dxgiFormat;
1363     if (!format.asDxgiFormat(&dxgiFormat)) {
1364         return {};
1365     }
1366 
1367     // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
1368     if (!caps.isFormatTexturable(dxgiFormat)) {
1369         return {};
1370     }
1371 
1372     GrD3DTextureResourceInfo info;
1373     if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
1374                                                       renderable, mipMapped, 1, &info,
1375                                                       isProtected)) {
1376         return {};
1377     }
1378 
1379     return GrBackendTexture(dimensions.width(), dimensions.height(), info);
1380 }
1381 
copy_color_data(const GrD3DCaps & caps,char * mapPtr,DXGI_FORMAT dxgiFormat,SkISize dimensions,D3D12_PLACED_SUBRESOURCE_FOOTPRINT * placedFootprints,std::array<float,4> color)1382 static bool copy_color_data(const GrD3DCaps& caps,
1383                             char* mapPtr,
1384                             DXGI_FORMAT dxgiFormat,
1385                             SkISize dimensions,
1386                             D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints,
1387                             std::array<float, 4> color) {
1388     auto colorType = caps.getFormatColorType(dxgiFormat);
1389     if (colorType == GrColorType::kUnknown) {
1390         return false;
1391     }
1392     GrImageInfo ii(colorType, kUnpremul_SkAlphaType, nullptr, dimensions);
1393     if (!GrClearImage(ii, mapPtr, placedFootprints[0].Footprint.RowPitch, color)) {
1394         return false;
1395     }
1396 
1397     return true;
1398 }
1399 
onClearBackendTexture(const GrBackendTexture & backendTexture,sk_sp<GrRefCntedCallback> finishedCallback,std::array<float,4> color)1400 bool GrD3DGpu::onClearBackendTexture(const GrBackendTexture& backendTexture,
1401                                      sk_sp<GrRefCntedCallback> finishedCallback,
1402                                      std::array<float, 4> color) {
1403     GrD3DTextureResourceInfo info;
1404     SkAssertResult(backendTexture.getD3DTextureResourceInfo(&info));
1405     SkASSERT(!GrDxgiFormatIsCompressed(info.fFormat));
1406 
1407     sk_sp<GrD3DResourceState> state = backendTexture.getGrD3DResourceState();
1408     SkASSERT(state);
1409     sk_sp<GrD3DTexture> texture =
1410             GrD3DTexture::MakeWrappedTexture(this, backendTexture.dimensions(),
1411                                              GrWrapCacheable::kNo,
1412                                              kRW_GrIOType, info, std::move(state));
1413     if (!texture) {
1414         return false;
1415     }
1416 
1417     GrD3DDirectCommandList* cmdList = this->currentCommandList();
1418     if (!cmdList) {
1419         return false;
1420     }
1421 
1422     texture->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
1423 
1424     ID3D12Resource* d3dResource = texture->d3dResource();
1425     SkASSERT(d3dResource);
1426     D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
1427     unsigned int mipLevelCount = 1;
1428     if (backendTexture.fMipmapped == GrMipmapped::kYes) {
1429         mipLevelCount = SkMipmap::ComputeLevelCount(backendTexture.dimensions()) + 1;
1430     }
1431     SkASSERT(mipLevelCount == info.fLevelCount);
1432     SkAutoSTMalloc<15, D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
1433     UINT numRows;
1434     UINT64 rowSizeInBytes;
1435     UINT64 combinedBufferSize;
1436     // We reuse the same top-level buffer area for all levels, hence passing 1 for level count.
1437     fDevice->GetCopyableFootprints(&desc,
1438                                    /* first resource  */ 0,
1439                                    /* mip level count */ 1,
1440                                    /* base offset     */ 0,
1441                                    placedFootprints.get(),
1442                                    &numRows,
1443                                    &rowSizeInBytes,
1444                                    &combinedBufferSize);
1445     SkASSERT(combinedBufferSize);
1446 
1447     GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
1448             combinedBufferSize, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
1449     if (!slice.fBuffer) {
1450         return false;
1451     }
1452 
1453     char* bufferData = (char*)slice.fOffsetMapPtr;
1454     SkASSERT(bufferData);
1455     if (!copy_color_data(this->d3dCaps(),
1456                          bufferData,
1457                          info.fFormat,
1458                          backendTexture.dimensions(),
1459                          placedFootprints,
1460                          color)) {
1461         return false;
1462     }
1463     // Update the offsets in the footprint to be relative to the slice's offset
1464     placedFootprints[0].Offset += slice.fOffset;
1465     // Since we're sharing data for all the levels, set all the upper level footprints to the base.
1466     UINT w = placedFootprints[0].Footprint.Width;
1467     UINT h = placedFootprints[0].Footprint.Height;
1468     for (unsigned int i = 1; i < mipLevelCount; ++i) {
1469         w = std::max(1U, w/2);
1470         h = std::max(1U, h/2);
1471         placedFootprints[i].Offset = placedFootprints[0].Offset;
1472         placedFootprints[i].Footprint.Format   = placedFootprints[0].Footprint.Format;
1473         placedFootprints[i].Footprint.Width    = w;
1474         placedFootprints[i].Footprint.Height   = h;
1475         placedFootprints[i].Footprint.Depth    = 1;
1476         placedFootprints[i].Footprint.RowPitch = placedFootprints[0].Footprint.RowPitch;
1477     }
1478 
1479     ID3D12Resource* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer)->d3dResource();
1480     cmdList->copyBufferToTexture(d3dBuffer,
1481                                  texture.get(),
1482                                  mipLevelCount,
1483                                  placedFootprints.get(),
1484                                  /*left*/ 0,
1485                                  /*top */ 0);
1486 
1487     if (finishedCallback) {
1488         this->addFinishedCallback(std::move(finishedCallback));
1489     }
1490 
1491     return true;
1492 }
1493 
onCreateCompressedBackendTexture(SkISize dimensions,const GrBackendFormat & format,GrMipmapped mipMapped,GrProtected isProtected)1494 GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(
1495     SkISize dimensions, const GrBackendFormat& format, GrMipmapped mipMapped,
1496     GrProtected isProtected) {
1497     return this->onCreateBackendTexture(dimensions, format, GrRenderable::kNo, mipMapped,
1498                                         isProtected);
1499 }
1500 
onUpdateCompressedBackendTexture(const GrBackendTexture & backendTexture,sk_sp<GrRefCntedCallback> finishedCallback,const void * data,size_t size)1501 bool GrD3DGpu::onUpdateCompressedBackendTexture(const GrBackendTexture& backendTexture,
1502                                                 sk_sp<GrRefCntedCallback> finishedCallback,
1503                                                 const void* data,
1504                                                 size_t size) {
1505     GrD3DTextureResourceInfo info;
1506     SkAssertResult(backendTexture.getD3DTextureResourceInfo(&info));
1507 
1508     sk_sp<GrD3DResourceState> state = backendTexture.getGrD3DResourceState();
1509     SkASSERT(state);
1510     sk_sp<GrD3DTexture> texture = GrD3DTexture::MakeWrappedTexture(this,
1511                                                                    backendTexture.dimensions(),
1512                                                                    GrWrapCacheable::kNo,
1513                                                                    kRW_GrIOType,
1514                                                                    info,
1515                                                                    std::move(state));
1516     if (!texture) {
1517         return false;
1518     }
1519 
1520     GrD3DDirectCommandList* cmdList = this->currentCommandList();
1521     if (!cmdList) {
1522         return false;
1523     }
1524 
1525     texture->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
1526 
1527     ID3D12Resource* d3dResource = texture->d3dResource();
1528     SkASSERT(d3dResource);
1529     D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
1530     unsigned int mipLevelCount = 1;
1531     if (backendTexture.hasMipmaps()) {
1532         mipLevelCount = SkMipmap::ComputeLevelCount(backendTexture.dimensions().width(),
1533                                                     backendTexture.dimensions().height()) + 1;
1534     }
1535     SkASSERT(mipLevelCount == info.fLevelCount);
1536     SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
1537     UINT64 combinedBufferSize;
1538     SkAutoTMalloc<UINT> numRows(mipLevelCount);
1539     SkAutoTMalloc<UINT64> rowSizeInBytes(mipLevelCount);
1540     fDevice->GetCopyableFootprints(&desc,
1541                                    0,
1542                                    mipLevelCount,
1543                                    0,
1544                                    placedFootprints.get(),
1545                                    numRows.get(),
1546                                    rowSizeInBytes.get(),
1547                                    &combinedBufferSize);
1548     SkASSERT(combinedBufferSize);
1549     SkASSERT(GrDxgiFormatIsCompressed(info.fFormat));
1550 
1551     GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
1552             combinedBufferSize, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
1553     if (!slice.fBuffer) {
1554         return false;
1555     }
1556 
1557     char* bufferData = (char*)slice.fOffsetMapPtr;
1558     SkASSERT(bufferData);
1559     copy_compressed_data(bufferData,
1560                          info.fFormat,
1561                          placedFootprints.get(),
1562                          numRows.get(),
1563                          rowSizeInBytes.get(),
1564                          data,
1565                          info.fLevelCount);
1566 
1567     // Update the offsets in the footprints to be relative to the slice's offset
1568     for (unsigned int i = 0; i < mipLevelCount; ++i) {
1569         placedFootprints[i].Offset += slice.fOffset;
1570     }
1571 
1572     ID3D12Resource* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer)->d3dResource();
1573     cmdList->copyBufferToTexture(d3dBuffer,
1574                                  texture.get(),
1575                                  mipLevelCount,
1576                                  placedFootprints.get(),
1577                                  0,
1578                                  0);
1579 
1580     if (finishedCallback) {
1581         this->addFinishedCallback(std::move(finishedCallback));
1582     }
1583 
1584     return true;
1585 }
1586 
deleteBackendTexture(const GrBackendTexture & tex)1587 void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
1588     SkASSERT(GrBackendApi::kDirect3D == tex.fBackend);
1589     // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
1590 }
1591 
compile(const GrProgramDesc &,const GrProgramInfo &)1592 bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
1593     return false;
1594 }
1595 
1596 #if GR_TEST_UTILS
isTestingOnlyBackendTexture(const GrBackendTexture & tex) const1597 bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
1598     SkASSERT(GrBackendApi::kDirect3D == tex.backend());
1599 
1600     GrD3DTextureResourceInfo info;
1601     if (!tex.getD3DTextureResourceInfo(&info)) {
1602         return false;
1603     }
1604     ID3D12Resource* textureResource = info.fResource.get();
1605     if (!textureResource) {
1606         return false;
1607     }
1608     return !(textureResource->GetDesc().Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
1609 }
1610 
createTestingOnlyBackendRenderTarget(SkISize dimensions,GrColorType colorType,int sampleCnt,GrProtected isProtected)1611 GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(SkISize dimensions,
1612                                                                      GrColorType colorType,
1613                                                                      int sampleCnt,
1614                                                                      GrProtected isProtected) {
1615     if (dimensions.width()  > this->caps()->maxRenderTargetSize() ||
1616         dimensions.height() > this->caps()->maxRenderTargetSize()) {
1617         return {};
1618     }
1619 
1620     DXGI_FORMAT dxgiFormat = this->d3dCaps().getFormatFromColorType(colorType);
1621 
1622     GrD3DTextureResourceInfo info;
1623     if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kNo,
1624                                                       GrRenderable::kYes, GrMipmapped::kNo,
1625                                                       sampleCnt, &info, isProtected)) {
1626         return {};
1627     }
1628 
1629     return GrBackendRenderTarget(dimensions.width(), dimensions.height(), info);
1630 }
1631 
deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget & rt)1632 void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
1633     SkASSERT(GrBackendApi::kDirect3D == rt.backend());
1634 
1635     GrD3DTextureResourceInfo info;
1636     if (rt.getD3DTextureResourceInfo(&info)) {
1637         this->submitToGpu(true);
1638         // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
1639         // is deleted.
1640     }
1641 }
1642 
testingOnly_startCapture()1643 void GrD3DGpu::testingOnly_startCapture() {
1644     if (fGraphicsAnalysis) {
1645         fGraphicsAnalysis->BeginCapture();
1646     }
1647 }
1648 
testingOnly_endCapture()1649 void GrD3DGpu::testingOnly_endCapture() {
1650     if (fGraphicsAnalysis) {
1651         fGraphicsAnalysis->EndCapture();
1652     }
1653 }
1654 #endif
1655 
1656 ///////////////////////////////////////////////////////////////////////////////
1657 
addResourceBarriers(sk_sp<GrManagedResource> resource,int numBarriers,D3D12_RESOURCE_TRANSITION_BARRIER * barriers) const1658 void GrD3DGpu::addResourceBarriers(sk_sp<GrManagedResource> resource,
1659                                    int numBarriers,
1660                                    D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
1661     SkASSERT(fCurrentDirectCommandList);
1662     SkASSERT(resource);
1663 
1664     fCurrentDirectCommandList->resourceBarrier(std::move(resource), numBarriers, barriers);
1665 }
1666 
addBufferResourceBarriers(GrD3DBuffer * buffer,int numBarriers,D3D12_RESOURCE_TRANSITION_BARRIER * barriers) const1667 void GrD3DGpu::addBufferResourceBarriers(GrD3DBuffer* buffer,
1668                                          int numBarriers,
1669                                          D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
1670     SkASSERT(fCurrentDirectCommandList);
1671     SkASSERT(buffer);
1672 
1673     fCurrentDirectCommandList->resourceBarrier(nullptr, numBarriers, barriers);
1674     fCurrentDirectCommandList->addGrBuffer(sk_ref_sp<const GrBuffer>(buffer));
1675 }
1676 
1677 
prepareSurfacesForBackendAccessAndStateUpdates(SkSpan<GrSurfaceProxy * > proxies,SkSurface::BackendSurfaceAccess access,const GrBackendSurfaceMutableState * newState)1678 void GrD3DGpu::prepareSurfacesForBackendAccessAndStateUpdates(
1679         SkSpan<GrSurfaceProxy*> proxies,
1680         SkSurface::BackendSurfaceAccess access,
1681         const GrBackendSurfaceMutableState* newState) {
1682     // prepare proxies by transitioning to PRESENT renderState
1683     if (!proxies.empty() && access == SkSurface::BackendSurfaceAccess::kPresent) {
1684         GrD3DTextureResource* resource;
1685         for (GrSurfaceProxy* proxy : proxies) {
1686             SkASSERT(proxy->isInstantiated());
1687             if (GrTexture* tex = proxy->peekTexture()) {
1688                 resource = static_cast<GrD3DTexture*>(tex);
1689             } else {
1690                 GrRenderTarget* rt = proxy->peekRenderTarget();
1691                 SkASSERT(rt);
1692                 resource = static_cast<GrD3DRenderTarget*>(rt);
1693             }
1694             resource->prepareForPresent(this);
1695         }
1696     }
1697 }
1698 
takeOwnershipOfBuffer(sk_sp<GrGpuBuffer> buffer)1699 void GrD3DGpu::takeOwnershipOfBuffer(sk_sp<GrGpuBuffer> buffer) {
1700     fCurrentDirectCommandList->addGrBuffer(std::move(buffer));
1701 }
1702 
onSubmitToGpu(bool syncCpu)1703 bool GrD3DGpu::onSubmitToGpu(bool syncCpu) {
1704     if (syncCpu) {
1705         return this->submitDirectCommandList(SyncQueue::kForce);
1706     } else {
1707         return this->submitDirectCommandList(SyncQueue::kSkip);
1708     }
1709 }
1710 
makeSemaphore(bool)1711 std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT GrD3DGpu::makeSemaphore(bool) {
1712     return GrD3DSemaphore::Make(this);
1713 }
wrapBackendSemaphore(const GrBackendSemaphore & semaphore,GrSemaphoreWrapType,GrWrapOwnership)1714 std::unique_ptr<GrSemaphore> GrD3DGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
1715                                                             GrSemaphoreWrapType /* wrapType */,
1716                                                             GrWrapOwnership /* ownership */) {
1717     SkASSERT(this->caps()->semaphoreSupport());
1718     GrD3DFenceInfo fenceInfo;
1719     if (!semaphore.getD3DFenceInfo(&fenceInfo)) {
1720         return nullptr;
1721     }
1722     return GrD3DSemaphore::MakeWrapped(fenceInfo);
1723 }
1724 
insertSemaphore(GrSemaphore * semaphore)1725 void GrD3DGpu::insertSemaphore(GrSemaphore* semaphore) {
1726     SkASSERT(semaphore);
1727     GrD3DSemaphore* d3dSem = static_cast<GrD3DSemaphore*>(semaphore);
1728     // TODO: Do we need to track the lifetime of this? How do we know it's done?
1729     fQueue->Signal(d3dSem->fence(), d3dSem->value());
1730 }
1731 
waitSemaphore(GrSemaphore * semaphore)1732 void GrD3DGpu::waitSemaphore(GrSemaphore* semaphore) {
1733     SkASSERT(semaphore);
1734     GrD3DSemaphore* d3dSem = static_cast<GrD3DSemaphore*>(semaphore);
1735     // TODO: Do we need to track the lifetime of this?
1736     fQueue->Wait(d3dSem->fence(), d3dSem->value());
1737 }
1738 
insertFence()1739 GrFence SK_WARN_UNUSED_RESULT GrD3DGpu::insertFence() {
1740     GR_D3D_CALL_ERRCHECK(fQueue->Signal(fFence.get(), ++fCurrentFenceValue));
1741     return fCurrentFenceValue;
1742 }
1743 
waitFence(GrFence fence)1744 bool GrD3DGpu::waitFence(GrFence fence) {
1745     return (fFence->GetCompletedValue() >= fence);
1746 }
1747 
finishOutstandingGpuWork()1748 void GrD3DGpu::finishOutstandingGpuWork() {
1749     this->waitForQueueCompletion();
1750 }
1751