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