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 33GrThreadSafePipelineBuilder* GrD3DGpu::pipelineBuilder() { 34 return nullptr; 35} 36 37sk_sp<GrThreadSafePipelineBuilder> GrD3DGpu::refPipelineBuilder() { 38 return nullptr; 39} 40 41 42sk_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. 62static const int kDefaultOutstandingAllocCnt = 8; 63 64// constants have to be aligned to 256 65constexpr int kConstantAlignment = 256; 66 67GrD3DGpu::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 97GrD3DGpu::~GrD3DGpu() { 98 this->destroyResources(); 99} 100 101void 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 127GrOpsRenderPass* 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 147bool 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 191void 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 210void 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 221void GrD3DGpu::submit(GrOpsRenderPass* renderPass) { 222 SkASSERT(fCachedOpsRenderPass.get() == renderPass); 223 224 fCachedOpsRenderPass->submit(); 225 fCachedOpsRenderPass.reset(); 226} 227 228void GrD3DGpu::endRenderPass(GrRenderTarget* target, GrSurfaceOrigin origin, 229 const SkIRect& bounds) { 230 this->didWriteToSurface(target, origin, &bounds); 231} 232 233void GrD3DGpu::addFinishedProc(GrGpuFinishedProc finishedProc, 234 GrGpuFinishedContext finishedContext) { 235 SkASSERT(finishedProc); 236 this->addFinishedCallback(GrRefCntedCallback::Make(finishedProc, finishedContext)); 237} 238 239void 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 254sk_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 296sk_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 325static 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 344sk_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 413sk_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 424static int get_surface_sample_cnt(GrSurface* surf) { 425 if (const GrRenderTarget* rt = surf->asRenderTarget()) { 426 return rt->numSamples(); 427 } 428 return 0; 429} 430 431bool 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 477void 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 528void 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 540void 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 563void 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 571bool 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 630void 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 664bool 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 697bool 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 792bool 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 860bool 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 913static bool check_resource_info(const GrD3DTextureResourceInfo& info) { 914 if (!info.fResource.get()) { 915 return false; 916 } 917 return true; 918} 919 920static 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 931static 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 939sk_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 967sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex, 968 GrWrapOwnership ownership, 969 GrWrapCacheable wrapType) { 970 return this->onWrapBackendTexture(tex, ownership, wrapType, kRead_GrIOType); 971} 972 973sk_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 1008sk_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 1041static 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 1051static bool is_bgra(DXGI_FORMAT format) { 1052 // the only one we support at the moment 1053 return (format == DXGI_FORMAT_B8G8R8A8_UNORM); 1054} 1055 1056bool 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 1263sk_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 1273sk_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 1281bool 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 1351GrBackendTexture 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 1382static 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 1400bool 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 1494GrBackendTexture 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 1501bool 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 1587void 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 1592bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) { 1593 return false; 1594} 1595 1596#if GR_TEST_UTILS 1597bool 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 1611GrBackendRenderTarget 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 1632void 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 1643void GrD3DGpu::testingOnly_startCapture() { 1644 if (fGraphicsAnalysis) { 1645 fGraphicsAnalysis->BeginCapture(); 1646 } 1647} 1648 1649void GrD3DGpu::testingOnly_endCapture() { 1650 if (fGraphicsAnalysis) { 1651 fGraphicsAnalysis->EndCapture(); 1652 } 1653} 1654#endif 1655 1656/////////////////////////////////////////////////////////////////////////////// 1657 1658void 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 1667void 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 1678void 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 1699void GrD3DGpu::takeOwnershipOfBuffer(sk_sp<GrGpuBuffer> buffer) { 1700 fCurrentDirectCommandList->addGrBuffer(std::move(buffer)); 1701} 1702 1703bool GrD3DGpu::onSubmitToGpu(bool syncCpu) { 1704 if (syncCpu) { 1705 return this->submitDirectCommandList(SyncQueue::kForce); 1706 } else { 1707 return this->submitDirectCommandList(SyncQueue::kSkip); 1708 } 1709} 1710 1711std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT GrD3DGpu::makeSemaphore(bool) { 1712 return GrD3DSemaphore::Make(this); 1713} 1714std::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 1725void 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 1732void 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 1739GrFence SK_WARN_UNUSED_RESULT GrD3DGpu::insertFence() { 1740 GR_D3D_CALL_ERRCHECK(fQueue->Signal(fFence.get(), ++fCurrentFenceValue)); 1741 return fCurrentFenceValue; 1742} 1743 1744bool GrD3DGpu::waitFence(GrFence fence) { 1745 return (fFence->GetCompletedValue() >= fence); 1746} 1747 1748void GrD3DGpu::finishOutstandingGpuWork() { 1749 this->waitForQueueCompletion(); 1750} 1751