blob: 6e2f79e85ceb13c91ab84e4c8de2b82a5829effb [file] [log] [blame]
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001/*
Jim Van Verth03b8ab22020-02-24 11:36:15 -05002 * Copyright 2020 Google LLC
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05003 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05008#include "src/gpu/d3d/GrD3DGpu.h"
9
Jim Van Verth96bfeff2020-04-09 14:36:12 -040010#include "include/gpu/GrBackendSurface.h"
Jim Van Verth9aa9a682020-04-01 10:13:48 -040011#include "include/gpu/d3d/GrD3DBackendContext.h"
Jim Van Verthc632aa62020-04-17 16:58:20 -040012#include "src/core/SkConvertPixels.h"
Jim Van Verth96bfeff2020-04-09 14:36:12 -040013#include "src/core/SkMipMap.h"
Jim Van Verthc632aa62020-04-17 16:58:20 -040014#include "src/gpu/GrDataUtils.h"
15#include "src/gpu/GrTexturePriv.h"
Jim Van Verthd6ad4802020-04-03 14:59:20 -040016#include "src/gpu/d3d/GrD3DBuffer.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050017#include "src/gpu/d3d/GrD3DCaps.h"
18#include "src/gpu/d3d/GrD3DOpsRenderPass.h"
Jim Van Verth4f51f472020-04-13 11:02:21 -040019#include "src/gpu/d3d/GrD3DStencilAttachment.h"
Jim Van Verthaa90dad2020-03-30 15:00:39 -040020#include "src/gpu/d3d/GrD3DTexture.h"
21#include "src/gpu/d3d/GrD3DTextureRenderTarget.h"
22#include "src/gpu/d3d/GrD3DUtil.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050023
Jim Van Verth9b5e16c2020-04-20 10:45:52 -040024#if GR_TEST_UTILS
25#include <DXProgrammableCapture.h>
26#endif
27
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050028sk_sp<GrGpu> GrD3DGpu::Make(const GrD3DBackendContext& backendContext,
29 const GrContextOptions& contextOptions, GrContext* context) {
30 return sk_sp<GrGpu>(new GrD3DGpu(context, contextOptions, backendContext));
31}
32
Greg Daniel83ed2132020-03-24 13:15:33 -040033// This constant determines how many OutstandingCommandLists are allocated together as a block in
34// the deque. As such it needs to balance allocating too much memory vs. incurring
35// allocation/deallocation thrashing. It should roughly correspond to the max number of outstanding
36// command lists we expect to see.
37static const int kDefaultOutstandingAllocCnt = 8;
38
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050039GrD3DGpu::GrD3DGpu(GrContext* context, const GrContextOptions& contextOptions,
40 const GrD3DBackendContext& backendContext)
Jim Van Verth03b8ab22020-02-24 11:36:15 -050041 : INHERITED(context)
42 , fDevice(backendContext.fDevice)
Greg Daniel02c45902020-03-09 10:58:09 -040043
44 , fQueue(backendContext.fQueue)
Greg Daniel83ed2132020-03-24 13:15:33 -040045 , fResourceProvider(this)
46 , fOutstandingCommandLists(sizeof(OutstandingCommandList), kDefaultOutstandingAllocCnt) {
Jim Van Verth8ec13302020-02-26 12:59:56 -050047 fCaps.reset(new GrD3DCaps(contextOptions,
Jim Van Verth9aa9a682020-04-01 10:13:48 -040048 backendContext.fAdapter.get(),
49 backendContext.fDevice.get()));
Greg Daniel85da3362020-03-09 15:18:35 -040050
51 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
Greg Daniele52c9782020-03-23 14:18:37 -040052 SkASSERT(fCurrentDirectCommandList);
Greg Daniel83ed2132020-03-24 13:15:33 -040053
54 SkASSERT(fCurrentFenceValue == 0);
55 SkDEBUGCODE(HRESULT hr = ) fDevice->CreateFence(fCurrentFenceValue, D3D12_FENCE_FLAG_NONE,
56 IID_PPV_ARGS(&fFence));
57 SkASSERT(SUCCEEDED(hr));
Jim Van Verth9b5e16c2020-04-20 10:45:52 -040058
59#if GR_TEST_UTILS
60 HRESULT getAnalysis = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&fGraphicsAnalysis));
61 if (FAILED(getAnalysis)) {
62 fGraphicsAnalysis = nullptr;
63 }
64#endif
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050065}
66
Greg Daniel83ed2132020-03-24 13:15:33 -040067GrD3DGpu::~GrD3DGpu() {
68 this->destroyResources();
69}
70
71void GrD3DGpu::destroyResources() {
72 if (fCurrentDirectCommandList) {
73 fCurrentDirectCommandList->close();
Jim Van Verthba7f2292020-04-21 08:56:47 -040074 fCurrentDirectCommandList->reset();
Greg Daniel83ed2132020-03-24 13:15:33 -040075 }
76
77 // We need to make sure everything has finished on the queue.
Jim Van Verthc632aa62020-04-17 16:58:20 -040078 this->waitForQueueCompletion();
Greg Daniel83ed2132020-03-24 13:15:33 -040079
80 SkDEBUGCODE(uint64_t fenceValue = fFence->GetCompletedValue();)
81
82 // We used a placement new for each object in fOutstandingCommandLists, so we're responsible
83 // for calling the destructor on each of them as well.
84 while (!fOutstandingCommandLists.empty()) {
85 OutstandingCommandList* list = (OutstandingCommandList*)fOutstandingCommandLists.back();
86 SkASSERT(list->fFenceValue <= fenceValue);
87 // No reason to recycle the command lists since we are destroying all resources anyways.
88 list->~OutstandingCommandList();
89 fOutstandingCommandLists.pop_back();
90 }
91}
Greg Daniel31a7b072020-02-26 15:31:49 -050092
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050093GrOpsRenderPass* GrD3DGpu::getOpsRenderPass(
94 GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds,
95 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
Greg Daniel31a7b072020-02-26 15:31:49 -050096 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050097 const SkTArray<GrSurfaceProxy*, true>& sampledProxies) {
Greg Daniel31a7b072020-02-26 15:31:49 -050098 if (!fCachedOpsRenderPass) {
99 fCachedOpsRenderPass.reset(new GrD3DOpsRenderPass(this));
100 }
101
102 if (!fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies)) {
103 return nullptr;
104 }
105 return fCachedOpsRenderPass.get();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500106}
107
Jim Van Verthc632aa62020-04-17 16:58:20 -0400108bool GrD3DGpu::submitDirectCommandList(SyncQueue sync) {
Greg Daniel83ed2132020-03-24 13:15:33 -0400109 SkASSERT(fCurrentDirectCommandList);
110
Jim Van Verthc632aa62020-04-17 16:58:20 -0400111 GrD3DDirectCommandList::SubmitResult result = fCurrentDirectCommandList->submit(fQueue.get());
112 if (result == GrD3DDirectCommandList::SubmitResult::kFailure) {
113 return false;
114 } else if (result == GrD3DDirectCommandList::SubmitResult::kNoWork) {
115 if (sync == SyncQueue::kForce) {
116 this->waitForQueueCompletion();
117 }
118 return true;
119 }
Greg Daniel83ed2132020-03-24 13:15:33 -0400120
121 new (fOutstandingCommandLists.push_back()) OutstandingCommandList(
122 std::move(fCurrentDirectCommandList), ++fCurrentFenceValue);
123
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400124 SkDEBUGCODE(HRESULT hr = ) fQueue->Signal(fFence.get(), fCurrentFenceValue);
Greg Daniel83ed2132020-03-24 13:15:33 -0400125 SkASSERT(SUCCEEDED(hr));
126
Jim Van Verthc632aa62020-04-17 16:58:20 -0400127 if (sync == SyncQueue::kForce) {
128 this->waitForQueueCompletion();
129 }
130
Greg Daniel83ed2132020-03-24 13:15:33 -0400131 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
132
133 // This should be done after we have a new command list in case the freeing of any resources
134 // held by a finished command list causes us send a new command to the gpu (like changing the
135 // resource state.
136 this->checkForFinishedCommandLists();
137
138 SkASSERT(fCurrentDirectCommandList);
Jim Van Verthc632aa62020-04-17 16:58:20 -0400139 return true;
Greg Daniel83ed2132020-03-24 13:15:33 -0400140}
141
142void GrD3DGpu::checkForFinishedCommandLists() {
143 uint64_t currentFenceValue = fFence->GetCompletedValue();
144
145 // Iterate over all the outstanding command lists to see if any have finished. The commands
146 // lists are in order from oldest to newest, so we start at the front to check if their fence
147 // value is less than the last signaled value. If so we pop it off and move onto the next.
148 // Repeat till we find a command list that has not finished yet (and all others afterwards are
149 // also guaranteed to not have finished).
150 SkDeque::F2BIter iter(fOutstandingCommandLists);
151 const OutstandingCommandList* curList = (const OutstandingCommandList*)iter.next();
152 while (curList && curList->fFenceValue <= currentFenceValue) {
153 curList = (const OutstandingCommandList*)iter.next();
154 OutstandingCommandList* front = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel7a5f1fa2020-03-24 14:50:19 -0400155 fResourceProvider.recycleDirectCommandList(std::move(front->fCommandList));
Greg Daniel83ed2132020-03-24 13:15:33 -0400156 // Since we used placement new we are responsible for calling the destructor manually.
157 front->~OutstandingCommandList();
158 fOutstandingCommandLists.pop_front();
159 }
160}
161
Jim Van Verthc632aa62020-04-17 16:58:20 -0400162void GrD3DGpu::waitForQueueCompletion() {
163 if (fFence->GetCompletedValue() < fCurrentFenceValue) {
164 HANDLE fenceEvent;
165 fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
166 SkASSERT(fenceEvent);
167 SkDEBUGCODE(HRESULT hr = ) fFence->SetEventOnCompletion(fCurrentFenceValue, fenceEvent);
168 SkASSERT(SUCCEEDED(hr));
169 WaitForSingleObject(fenceEvent, INFINITE);
170 CloseHandle(fenceEvent);
171 }
172}
173
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500174void GrD3DGpu::submit(GrOpsRenderPass* renderPass) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400175 SkASSERT(fCachedOpsRenderPass.get() == renderPass);
176
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500177 // TODO: actually submit something here
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400178 fCachedOpsRenderPass.reset();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500179}
180
181void GrD3DGpu::querySampleLocations(GrRenderTarget* rt, SkTArray<SkPoint>* sampleLocations) {
182 // TODO
183}
184
185sk_sp<GrTexture> GrD3DGpu::onCreateTexture(SkISize dimensions,
186 const GrBackendFormat& format,
187 GrRenderable renderable,
188 int renderTargetSampleCnt,
189 SkBudgeted budgeted,
190 GrProtected isProtected,
191 int mipLevelCount,
192 uint32_t levelClearMask) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400193 DXGI_FORMAT dxgiFormat;
194 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
195 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
196
197 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
198
199 if (renderable == GrRenderable::kYes) {
200 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
201 }
202
203 // This desc refers to the texture that will be read by the client. Thus even if msaa is
204 // requested, this describes the resolved texture. Therefore we always have samples set
205 // to 1.
206 SkASSERT(mipLevelCount > 0);
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400207 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400208 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
209 // TODO: will use 4MB alignment for MSAA textures and 64KB for everything else
210 // might want to manually set alignment to 4KB for smaller textures
211 resourceDesc.Alignment = 0;
212 resourceDesc.Width = dimensions.fWidth;
213 resourceDesc.Height = dimensions.fHeight;
214 resourceDesc.DepthOrArraySize = 1;
215 resourceDesc.MipLevels = mipLevelCount;
216 resourceDesc.Format = dxgiFormat;
217 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400218 // quality levels are only supported for tiled resources so ignore for now
219 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400220 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400221 resourceDesc.Flags = usageFlags;
222
223 GrMipMapsStatus mipMapsStatus =
224 mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
225
226 sk_sp<GrD3DTexture> tex;
227 if (renderable == GrRenderable::kYes) {
228 tex = GrD3DTextureRenderTarget::MakeNewTextureRenderTarget(
229 this, budgeted, dimensions, renderTargetSampleCnt, resourceDesc, isProtected,
230 mipMapsStatus);
231 } else {
232 tex = GrD3DTexture::MakeNewTexture(this, budgeted, dimensions, resourceDesc, isProtected,
233 mipMapsStatus);
234 }
235
236 if (!tex) {
237 return nullptr;
238 }
239
240 if (levelClearMask) {
241 // TODO
242 }
243 return std::move(tex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500244}
245
246sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
247 const GrBackendFormat& format,
248 SkBudgeted budgeted,
249 GrMipMapped mipMapped,
250 GrProtected isProtected,
251 const void* data, size_t dataSize) {
252 // TODO
253 return nullptr;
254}
255
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400256static bool check_resource_info(const GrD3DTextureResourceInfo& info) {
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400257 if (!info.fResource.get()) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400258 return false;
259 }
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400260 return true;
261}
262
Jim Van Verthba7f2292020-04-21 08:56:47 -0400263bool GrD3DGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
264 GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
265 size_t rowBytes) {
266 SkASSERT(surface);
267
268 if (surfaceColorType != dstColorType) {
269 return false;
270 }
271
272 // Set up src location and box
273 GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
274 if (!d3dTex) {
275 return false;
276 }
277 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
278 srcLocation.pResource = d3dTex->d3dResource();
279 SkASSERT(srcLocation.pResource);
280 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
281 srcLocation.SubresourceIndex = 0;
282
283 D3D12_BOX srcBox = {};
284 srcBox.left = left;
285 srcBox.top = top;
286 srcBox.right = left + width;
287 srcBox.bottom = top + height;
288 srcBox.front = 0;
289 srcBox.back = 1;
290
291 // Set up dst location and create transfer buffer
292 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
293 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
294 UINT transferNumRows;
295 UINT64 transferRowBytes;
296 UINT64 transferTotalBytes;
297 const UINT64 baseOffset = 0;
298 D3D12_RESOURCE_DESC desc = srcLocation.pResource->GetDesc();
299 fDevice->GetCopyableFootprints(&desc, 0, 1, baseOffset, &dstLocation.PlacedFootprint,
300 &transferNumRows, &transferRowBytes, &transferTotalBytes);
301 SkASSERT(transferTotalBytes);
302
303 // TODO: implement some way of reusing buffers instead of making a new one every time.
304 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(transferTotalBytes,
305 GrGpuBufferType::kXferGpuToCpu,
306 kDynamic_GrAccessPattern);
307 GrD3DBuffer* d3dBuf = static_cast<GrD3DBuffer*>(transferBuffer.get());
308 dstLocation.pResource = d3dBuf->d3dResource();
309
310 // Need to change the resource state to COPY_SOURCE in order to download from it
311 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
312
313 fCurrentDirectCommandList->copyTextureRegion(d3dBuf->resource(), &dstLocation, 0, 0,
314 d3dTex->resource(), &srcLocation, &srcBox);
315 this->submitDirectCommandList(SyncQueue::kForce);
316
317 const void* mappedMemory = transferBuffer->map();
318
319 SkRectMemcpy(buffer, rowBytes, mappedMemory, dstLocation.PlacedFootprint.Footprint.RowPitch,
320 transferRowBytes, transferNumRows);
321
322 transferBuffer->unmap();
323
324 return true;
325}
326
327bool GrD3DGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
328 GrColorType surfaceColorType, GrColorType srcColorType,
329 const GrMipLevel texels[], int mipLevelCount,
330 bool prepForTexSampling) {
331 GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
332 if (!d3dTex) {
333 return false;
334 }
335
336 // Make sure we have at least the base level
337 if (!mipLevelCount || !texels[0].fPixels) {
338 return false;
339 }
340
341 SkASSERT(!GrDxgiFormatIsCompressed(d3dTex->dxgiFormat()));
342 bool success = false;
343
344 // Need to change the resource state to COPY_DEST in order to upload to it
345 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
346
347 SkASSERT(mipLevelCount <= d3dTex->texturePriv().maxMipMapLevel() + 1);
348 success = this->uploadToTexture(d3dTex, left, top, width, height, srcColorType, texels,
349 mipLevelCount);
350
351 if (prepForTexSampling) {
352 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
353 }
354
355 return success;
356}
357
358bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex, int left, int top, int width, int height,
359 GrColorType colorType, const GrMipLevel* texels, int mipLevelCount) {
360 SkASSERT(this->caps()->isFormatTexturable(tex->backendFormat()));
361 // The assumption is either that we have no mipmaps, or that our rect is the entire texture
362 SkASSERT(1 == mipLevelCount ||
363 (0 == left && 0 == top && width == tex->width() && height == tex->height()));
364
365 // We assume that if the texture has mip levels, we either upload to all the levels or just the
366 // first.
367 SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
368
369 if (width == 0 || height == 0) {
370 return false;
371 }
372
373 SkASSERT(this->d3dCaps().surfaceSupportsWritePixels(tex));
374 SkASSERT(this->d3dCaps().areColorTypeAndFormatCompatible(colorType, tex->backendFormat()));
375
376 ID3D12Resource* d3dResource = tex->d3dResource();
377 SkASSERT(d3dResource);
378 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
379 // Either upload only the first miplevel or all miplevels
380 SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
381
382 if (1 == mipLevelCount && !texels[0].fPixels) {
383 return true; // no data to upload
384 }
385
386 for (int i = 0; i < mipLevelCount; ++i) {
387 // We do not allow any gaps in the mip data
388 if (!texels[i].fPixels) {
389 return false;
390 }
391 }
392
393 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
394 SkAutoTMalloc<UINT> numRows(mipLevelCount);
395 SkAutoTMalloc<UINT64> rowBytes(mipLevelCount);
396 UINT64 combinedBufferSize;
397 // We reset the width and height in the description to match our subrectangle size
398 // so we don't end up allocating more space than we need.
399 desc.Width = width;
400 desc.Height = height;
401 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
402 numRows.get(), rowBytes.get(), &combinedBufferSize);
403 SkASSERT(combinedBufferSize);
404
405 // TODO: do this until we have slices of buttery buffers
406 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(combinedBufferSize,
407 GrGpuBufferType::kXferCpuToGpu,
408 kDynamic_GrAccessPattern);
409 if (!transferBuffer) {
410 return false;
411 }
412 char* bufferData = (char*)transferBuffer->map();
413
414 int currentWidth = width;
415 int currentHeight = height;
416 int layerHeight = tex->height();
417
418 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
419 if (texels[currentMipLevel].fPixels) {
420 SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
421
422 const size_t trimRowBytes = rowBytes[currentMipLevel];
423 const size_t srcRowBytes = texels[currentMipLevel].fRowBytes;
424
425 char* dst = bufferData + placedFootprints[currentMipLevel].Offset;
426
427 // copy data into the buffer, skipping any trailing bytes
428
429 const char* src = (const char*)texels[currentMipLevel].fPixels;
430 SkASSERT(currentHeight == (int)numRows[currentMipLevel]);
431 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
432 src, srcRowBytes, trimRowBytes, currentHeight);
433 }
434 currentWidth = std::max(1, currentWidth / 2);
435 currentHeight = std::max(1, currentHeight / 2);
436 layerHeight = currentHeight;
437 }
438
439 transferBuffer->unmap();
440
441 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get());
442 fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, tex, mipLevelCount,
443 placedFootprints.get(), left, top);
444
445 if (mipLevelCount < (int)desc.MipLevels) {
446 tex->texturePriv().markMipMapsDirty();
447 }
448
449 return true;
450}
451
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400452static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
453 if (!caps.isFormatTexturable(info.fFormat)) {
454 return false;
455 }
456 return true;
457}
458
459static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
460 int sampleCnt) {
461 if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
462 return false;
463 }
464 return true;
465}
466
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400467sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
468 GrWrapOwnership,
469 GrWrapCacheable wrapType,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400470 GrIOType ioType) {
471 GrD3DTextureResourceInfo textureInfo;
472 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
473 return nullptr;
474 }
475
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400476 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400477 return nullptr;
478 }
479
480 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
481 return nullptr;
482 }
483
484 // TODO: support protected context
485 if (tex.isProtected()) {
486 return nullptr;
487 }
488
489 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
490 SkASSERT(state);
491 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
492 std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500493}
494
495sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400496 GrWrapOwnership,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500497 GrWrapCacheable wrapType) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400498 GrD3DTextureResourceInfo textureInfo;
499 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
500 return nullptr;
501 }
502
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400503 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400504 return nullptr;
505 }
506
507 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
508 return nullptr;
509 }
510
511 // TODO: support protected context
512 if (tex.isProtected()) {
513 return nullptr;
514 }
515
516 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
517 SkASSERT(state);
518 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, kRead_GrIOType,
519 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500520}
521
522sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
523 int sampleCnt,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500524 GrWrapOwnership ownership,
525 GrWrapCacheable cacheable) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400526 GrD3DTextureResourceInfo textureInfo;
527 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
528 return nullptr;
529 }
530
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400531 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400532 return nullptr;
533 }
534
535 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
536 return nullptr;
537 }
538 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
539 return nullptr;
540 }
541
542 // TODO: support protected context
543 if (tex.isProtected()) {
544 return nullptr;
545 }
546
547 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
548
549 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
550 SkASSERT(state);
551
552 return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
553 sampleCnt, cacheable,
554 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500555}
556
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400557sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400558 // Currently the Direct3D backend does not support wrapping of msaa render targets directly. In
559 // general this is not an issue since swapchain images in D3D are never multisampled. Thus if
560 // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
561 // creating and owning the MSAA images.
562 if (rt.sampleCnt() > 1) {
563 return nullptr;
564 }
565
566 GrD3DTextureResourceInfo info;
567 if (!rt.getD3DTextureResourceInfo(&info)) {
568 return nullptr;
569 }
570
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400571 if (!check_resource_info(info)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400572 return nullptr;
573 }
574
575 if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
576 return nullptr;
577 }
578
579 // TODO: support protected context
580 if (rt.isProtected()) {
581 return nullptr;
582 }
583
584 sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
585
586 sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
587 this, rt.dimensions(), 1, info, std::move(state));
588
589 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
590 SkASSERT(!rt.stencilBits());
591 if (tgt) {
592 SkASSERT(tgt->canAttemptStencilAttachment());
593 }
594
595 return std::move(tgt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500596}
597
598sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400599 int sampleCnt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400600
601 GrD3DTextureResourceInfo textureInfo;
602 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
603 return nullptr;
604 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400605 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400606 return nullptr;
607 }
608
609 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
610 return nullptr;
611 }
612
613 // TODO: support protected context
614 if (tex.isProtected()) {
615 return nullptr;
616 }
617
618 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
619 if (!sampleCnt) {
620 return nullptr;
621 }
622
623 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
624 SkASSERT(state);
625
626 return GrD3DRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt,
627 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500628}
629
630sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
Jim Van Verthd6ad4802020-04-03 14:59:20 -0400631 GrAccessPattern accessPattern, const void* data) {
632 sk_sp<GrD3DBuffer> buffer = GrD3DBuffer::Make(this, sizeInBytes, type, accessPattern);
633 if (data && buffer) {
634 buffer->updateData(data, sizeInBytes);
635 }
636
637 return std::move(buffer);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500638}
639
640GrStencilAttachment* GrD3DGpu::createStencilAttachmentForRenderTarget(
641 const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
Jim Van Verth4f51f472020-04-13 11:02:21 -0400642 SkASSERT(numStencilSamples == rt->numSamples() || this->caps()->mixedSamplesSupport());
643 SkASSERT(width >= rt->width());
644 SkASSERT(height >= rt->height());
645
646 const GrD3DCaps::StencilFormat& sFmt = this->d3dCaps().preferredStencilFormat();
647
648 GrD3DStencilAttachment* stencil(GrD3DStencilAttachment::Make(this,
649 width,
650 height,
651 numStencilSamples,
652 sFmt));
653 fStats.incStencilAttachmentCreates();
654 return stencil;
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500655}
656
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400657bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
658 SkISize dimensions,
659 GrTexturable texturable,
660 GrRenderable renderable,
661 GrMipMapped mipMapped,
662 GrD3DTextureResourceInfo* info,
663 GrProtected isProtected,
664 const BackendTextureData* data) {
665 SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
666 if (texturable == GrTexturable::kNo) {
667 SkASSERT(!data && mipMapped == GrMipMapped::kNo);
668 }
669
670 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
671 return false;
672 }
673
674 if (texturable == GrTexturable::kYes && !this->d3dCaps().isFormatTexturable(dxgiFormat)) {
675 return false;
676 }
677
678 if (renderable == GrRenderable::kYes && !this->d3dCaps().isFormatRenderable(dxgiFormat, 1)) {
679 return false;
680 }
681
682 int numMipLevels = 1;
683 if (mipMapped == GrMipMapped::kYes) {
684 numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
685 }
686
687 // create the texture
688 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
689 if (renderable == GrRenderable::kYes) {
690 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
691 }
692
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400693 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400694 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
695 resourceDesc.Alignment = 0; // use default alignment
696 resourceDesc.Width = dimensions.fWidth;
697 resourceDesc.Height = dimensions.fHeight;
698 resourceDesc.DepthOrArraySize = 1;
699 resourceDesc.MipLevels = numMipLevels;
700 resourceDesc.Format = dxgiFormat;
701 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400702 // quality levels are only supported for tiled resources so ignore for now
703 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400704 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
705 resourceDesc.Flags = usageFlags;
706
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400707 D3D12_RESOURCE_STATES initialState =
708 (renderable == GrRenderable::kYes) && !data ? D3D12_RESOURCE_STATE_RENDER_TARGET :
709 D3D12_RESOURCE_STATE_COPY_DEST;
710 if (!GrD3DTextureResource::InitTextureResourceInfo(this, resourceDesc, initialState,
711 isProtected, info)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400712 SkDebugf("Failed to init texture resource info\n");
713 return false;
714 }
715
716 if (!data) {
717 return true;
718 }
719
720 // TODO: upload the data
721
722 return true;
723}
724
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500725GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400726 const GrBackendFormat& format,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400727 GrRenderable renderable,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400728 GrMipMapped mipMapped,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400729 GrProtected isProtected,
730 const BackendTextureData* data) {
731 this->handleDirtyContext();
732
733 const GrD3DCaps& caps = this->d3dCaps();
734
735 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
736 return {};
737 }
738
739 DXGI_FORMAT dxgiFormat;
740 if (!format.asDxgiFormat(&dxgiFormat)) {
741 return {};
742 }
743
744 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
745 if (!caps.isFormatTexturable(dxgiFormat)) {
746 return {};
747 }
748
749 GrD3DTextureResourceInfo info;
750 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
751 renderable, mipMapped,
752 &info, isProtected, data)) {
753 return {};
754 }
755
756 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500757}
758
759GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400760 const GrBackendFormat& format,
761 GrMipMapped mipMapped,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400762 GrProtected isProtected,
763 const BackendTextureData* data) {
764 this->handleDirtyContext();
765
766 const GrD3DCaps& caps = this->d3dCaps();
767
768 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
769 return {};
770 }
771
772 DXGI_FORMAT dxgiFormat;
773 if (!format.asDxgiFormat(&dxgiFormat)) {
774 return {};
775 }
776
777 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
778 if (!caps.isFormatTexturable(dxgiFormat)) {
779 return {};
780 }
781
782 GrD3DTextureResourceInfo info;
783 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
784 GrRenderable::kNo, mipMapped,
785 &info, isProtected, data)) {
786 return {};
787 }
788
789 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500790}
791
792void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400793 SkASSERT(GrBackendApi::kDirect3D == tex.fBackend);
794 // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500795}
796
Robert Phillips979b2232020-02-20 10:47:29 -0500797bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
798 return false;
799}
800
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500801#if GR_TEST_UTILS
802bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400803 SkASSERT(GrBackendApi::kDirect3D == tex.backend());
804
805 GrD3DTextureResourceInfo info;
806 if (!tex.getD3DTextureResourceInfo(&info)) {
807 return false;
808 }
809 ID3D12Resource* textureResource = info.fResource.get();
810 if (!textureResource) {
811 return false;
812 }
813 return !(textureResource->GetDesc().Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500814}
815
816GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(int w, int h,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400817 GrColorType colorType) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400818 this->handleDirtyContext();
819
820 if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400821 return {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400822 }
823
824 DXGI_FORMAT dxgiFormat = this->d3dCaps().getFormatFromColorType(colorType);
825
826 GrD3DTextureResourceInfo info;
827 if (!this->createTextureResourceForBackendSurface(dxgiFormat, { w, h }, GrTexturable::kNo,
828 GrRenderable::kYes, GrMipMapped::kNo,
829 &info, GrProtected::kNo, nullptr)) {
830 return {};
831 }
832
833 return GrBackendRenderTarget(w, h, 1, info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500834}
835
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400836void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
837 SkASSERT(GrBackendApi::kDirect3D == rt.backend());
838
839 GrD3DTextureResourceInfo info;
840 if (rt.getD3DTextureResourceInfo(&info)) {
841 this->testingOnly_flushGpuAndSync();
842 // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
843 // is deleted.
844 }
845}
846
847void GrD3DGpu::testingOnly_flushGpuAndSync() {
Jim Van Verthc632aa62020-04-17 16:58:20 -0400848 SkAssertResult(this->submitDirectCommandList(SyncQueue::kForce));
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400849}
Jim Van Verthc632aa62020-04-17 16:58:20 -0400850
Jim Van Verth9b5e16c2020-04-20 10:45:52 -0400851void GrD3DGpu::testingOnly_startCapture() {
852 if (fGraphicsAnalysis) {
853 fGraphicsAnalysis->BeginCapture();
854 }
855}
856
857void GrD3DGpu::testingOnly_endCapture() {
858 if (fGraphicsAnalysis) {
859 fGraphicsAnalysis->EndCapture();
860 }
861}
862#endif
863
Jim Van Verthc632aa62020-04-17 16:58:20 -0400864///////////////////////////////////////////////////////////////////////////////
865
866void GrD3DGpu::addResourceBarriers(const GrManagedResource* resource,
867 int numBarriers,
868 D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
869 SkASSERT(fCurrentDirectCommandList);
870 SkASSERT(resource);
871
872 fCurrentDirectCommandList->resourceBarrier(resource, numBarriers, barriers);
873}
874
875bool GrD3DGpu::onSubmitToGpu(bool syncCpu) {
876 if (syncCpu) {
877 return this->submitDirectCommandList(SyncQueue::kForce);
878 } else {
879 return this->submitDirectCommandList(SyncQueue::kSkip);
880 }
881}