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