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