blob: 2725761b2431cb926df897a0731acb3958672ed9 [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 Daniel5fc5c812020-04-23 10:30:23 -040023#include "src/sksl/SkSLCompiler.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050024
Jim Van Verth9b5e16c2020-04-20 10:45:52 -040025#if GR_TEST_UTILS
26#include <DXProgrammableCapture.h>
27#endif
28
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050029sk_sp<GrGpu> GrD3DGpu::Make(const GrD3DBackendContext& backendContext,
30 const GrContextOptions& contextOptions, GrContext* context) {
31 return sk_sp<GrGpu>(new GrD3DGpu(context, contextOptions, backendContext));
32}
33
Greg Daniel83ed2132020-03-24 13:15:33 -040034// This constant determines how many OutstandingCommandLists are allocated together as a block in
35// the deque. As such it needs to balance allocating too much memory vs. incurring
36// allocation/deallocation thrashing. It should roughly correspond to the max number of outstanding
37// command lists we expect to see.
38static const int kDefaultOutstandingAllocCnt = 8;
39
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050040GrD3DGpu::GrD3DGpu(GrContext* context, const GrContextOptions& contextOptions,
41 const GrD3DBackendContext& backendContext)
Jim Van Verth03b8ab22020-02-24 11:36:15 -050042 : INHERITED(context)
43 , fDevice(backendContext.fDevice)
Greg Daniel02c45902020-03-09 10:58:09 -040044
45 , fQueue(backendContext.fQueue)
Greg Daniel83ed2132020-03-24 13:15:33 -040046 , fResourceProvider(this)
Greg Daniel5fc5c812020-04-23 10:30:23 -040047 , fOutstandingCommandLists(sizeof(OutstandingCommandList), kDefaultOutstandingAllocCnt)
48 , fCompiler(new SkSL::Compiler()) {
Jim Van Verth8ec13302020-02-26 12:59:56 -050049 fCaps.reset(new GrD3DCaps(contextOptions,
Jim Van Verth9aa9a682020-04-01 10:13:48 -040050 backendContext.fAdapter.get(),
51 backendContext.fDevice.get()));
Greg Daniel85da3362020-03-09 15:18:35 -040052
53 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
Greg Daniele52c9782020-03-23 14:18:37 -040054 SkASSERT(fCurrentDirectCommandList);
Greg Daniel83ed2132020-03-24 13:15:33 -040055
56 SkASSERT(fCurrentFenceValue == 0);
57 SkDEBUGCODE(HRESULT hr = ) fDevice->CreateFence(fCurrentFenceValue, D3D12_FENCE_FLAG_NONE,
58 IID_PPV_ARGS(&fFence));
59 SkASSERT(SUCCEEDED(hr));
Jim Van Verth9b5e16c2020-04-20 10:45:52 -040060
61#if GR_TEST_UTILS
62 HRESULT getAnalysis = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&fGraphicsAnalysis));
63 if (FAILED(getAnalysis)) {
64 fGraphicsAnalysis = nullptr;
65 }
66#endif
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050067}
68
Greg Daniel83ed2132020-03-24 13:15:33 -040069GrD3DGpu::~GrD3DGpu() {
70 this->destroyResources();
71}
72
73void GrD3DGpu::destroyResources() {
74 if (fCurrentDirectCommandList) {
75 fCurrentDirectCommandList->close();
Jim Van Verthba7f2292020-04-21 08:56:47 -040076 fCurrentDirectCommandList->reset();
Greg Daniel83ed2132020-03-24 13:15:33 -040077 }
78
79 // We need to make sure everything has finished on the queue.
Jim Van Verthc632aa62020-04-17 16:58:20 -040080 this->waitForQueueCompletion();
Greg Daniel83ed2132020-03-24 13:15:33 -040081
82 SkDEBUGCODE(uint64_t fenceValue = fFence->GetCompletedValue();)
83
84 // We used a placement new for each object in fOutstandingCommandLists, so we're responsible
85 // for calling the destructor on each of them as well.
86 while (!fOutstandingCommandLists.empty()) {
87 OutstandingCommandList* list = (OutstandingCommandList*)fOutstandingCommandLists.back();
88 SkASSERT(list->fFenceValue <= fenceValue);
89 // No reason to recycle the command lists since we are destroying all resources anyways.
90 list->~OutstandingCommandList();
91 fOutstandingCommandLists.pop_back();
92 }
93}
Greg Daniel31a7b072020-02-26 15:31:49 -050094
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050095GrOpsRenderPass* GrD3DGpu::getOpsRenderPass(
96 GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds,
97 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
Greg Daniel31a7b072020-02-26 15:31:49 -050098 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050099 const SkTArray<GrSurfaceProxy*, true>& sampledProxies) {
Greg Daniel31a7b072020-02-26 15:31:49 -0500100 if (!fCachedOpsRenderPass) {
101 fCachedOpsRenderPass.reset(new GrD3DOpsRenderPass(this));
102 }
103
104 if (!fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies)) {
105 return nullptr;
106 }
107 return fCachedOpsRenderPass.get();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500108}
109
Jim Van Verthc632aa62020-04-17 16:58:20 -0400110bool GrD3DGpu::submitDirectCommandList(SyncQueue sync) {
Greg Daniel83ed2132020-03-24 13:15:33 -0400111 SkASSERT(fCurrentDirectCommandList);
112
Jim Van Verthc632aa62020-04-17 16:58:20 -0400113 GrD3DDirectCommandList::SubmitResult result = fCurrentDirectCommandList->submit(fQueue.get());
114 if (result == GrD3DDirectCommandList::SubmitResult::kFailure) {
115 return false;
116 } else if (result == GrD3DDirectCommandList::SubmitResult::kNoWork) {
117 if (sync == SyncQueue::kForce) {
118 this->waitForQueueCompletion();
119 }
120 return true;
121 }
Greg Daniel83ed2132020-03-24 13:15:33 -0400122
123 new (fOutstandingCommandLists.push_back()) OutstandingCommandList(
124 std::move(fCurrentDirectCommandList), ++fCurrentFenceValue);
125
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400126 SkDEBUGCODE(HRESULT hr = ) fQueue->Signal(fFence.get(), fCurrentFenceValue);
Greg Daniel83ed2132020-03-24 13:15:33 -0400127 SkASSERT(SUCCEEDED(hr));
128
Jim Van Verthc632aa62020-04-17 16:58:20 -0400129 if (sync == SyncQueue::kForce) {
130 this->waitForQueueCompletion();
131 }
132
Greg Daniel83ed2132020-03-24 13:15:33 -0400133 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
134
135 // This should be done after we have a new command list in case the freeing of any resources
136 // held by a finished command list causes us send a new command to the gpu (like changing the
137 // resource state.
138 this->checkForFinishedCommandLists();
139
140 SkASSERT(fCurrentDirectCommandList);
Jim Van Verthc632aa62020-04-17 16:58:20 -0400141 return true;
Greg Daniel83ed2132020-03-24 13:15:33 -0400142}
143
144void GrD3DGpu::checkForFinishedCommandLists() {
145 uint64_t currentFenceValue = fFence->GetCompletedValue();
146
147 // Iterate over all the outstanding command lists to see if any have finished. The commands
148 // lists are in order from oldest to newest, so we start at the front to check if their fence
149 // value is less than the last signaled value. If so we pop it off and move onto the next.
150 // Repeat till we find a command list that has not finished yet (and all others afterwards are
151 // also guaranteed to not have finished).
152 SkDeque::F2BIter iter(fOutstandingCommandLists);
153 const OutstandingCommandList* curList = (const OutstandingCommandList*)iter.next();
154 while (curList && curList->fFenceValue <= currentFenceValue) {
155 curList = (const OutstandingCommandList*)iter.next();
156 OutstandingCommandList* front = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel7a5f1fa2020-03-24 14:50:19 -0400157 fResourceProvider.recycleDirectCommandList(std::move(front->fCommandList));
Greg Daniel83ed2132020-03-24 13:15:33 -0400158 // Since we used placement new we are responsible for calling the destructor manually.
159 front->~OutstandingCommandList();
160 fOutstandingCommandLists.pop_front();
161 }
162}
163
Jim Van Verthc632aa62020-04-17 16:58:20 -0400164void GrD3DGpu::waitForQueueCompletion() {
165 if (fFence->GetCompletedValue() < fCurrentFenceValue) {
166 HANDLE fenceEvent;
167 fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
168 SkASSERT(fenceEvent);
169 SkDEBUGCODE(HRESULT hr = ) fFence->SetEventOnCompletion(fCurrentFenceValue, fenceEvent);
170 SkASSERT(SUCCEEDED(hr));
171 WaitForSingleObject(fenceEvent, INFINITE);
172 CloseHandle(fenceEvent);
173 }
174}
175
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500176void GrD3DGpu::submit(GrOpsRenderPass* renderPass) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400177 SkASSERT(fCachedOpsRenderPass.get() == renderPass);
178
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500179 // TODO: actually submit something here
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400180 fCachedOpsRenderPass.reset();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500181}
182
183void GrD3DGpu::querySampleLocations(GrRenderTarget* rt, SkTArray<SkPoint>* sampleLocations) {
184 // TODO
185}
186
187sk_sp<GrTexture> GrD3DGpu::onCreateTexture(SkISize dimensions,
188 const GrBackendFormat& format,
189 GrRenderable renderable,
190 int renderTargetSampleCnt,
191 SkBudgeted budgeted,
192 GrProtected isProtected,
193 int mipLevelCount,
194 uint32_t levelClearMask) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400195 DXGI_FORMAT dxgiFormat;
196 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
197 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
198
199 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
200
201 if (renderable == GrRenderable::kYes) {
202 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
203 }
204
205 // This desc refers to the texture that will be read by the client. Thus even if msaa is
206 // requested, this describes the resolved texture. Therefore we always have samples set
207 // to 1.
208 SkASSERT(mipLevelCount > 0);
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400209 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400210 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
211 // TODO: will use 4MB alignment for MSAA textures and 64KB for everything else
212 // might want to manually set alignment to 4KB for smaller textures
213 resourceDesc.Alignment = 0;
214 resourceDesc.Width = dimensions.fWidth;
215 resourceDesc.Height = dimensions.fHeight;
216 resourceDesc.DepthOrArraySize = 1;
217 resourceDesc.MipLevels = mipLevelCount;
218 resourceDesc.Format = dxgiFormat;
219 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400220 // quality levels are only supported for tiled resources so ignore for now
221 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400222 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400223 resourceDesc.Flags = usageFlags;
224
225 GrMipMapsStatus mipMapsStatus =
226 mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
227
228 sk_sp<GrD3DTexture> tex;
229 if (renderable == GrRenderable::kYes) {
230 tex = GrD3DTextureRenderTarget::MakeNewTextureRenderTarget(
231 this, budgeted, dimensions, renderTargetSampleCnt, resourceDesc, isProtected,
232 mipMapsStatus);
233 } else {
234 tex = GrD3DTexture::MakeNewTexture(this, budgeted, dimensions, resourceDesc, isProtected,
235 mipMapsStatus);
236 }
237
238 if (!tex) {
239 return nullptr;
240 }
241
242 if (levelClearMask) {
243 // TODO
244 }
245 return std::move(tex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500246}
247
248sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
249 const GrBackendFormat& format,
250 SkBudgeted budgeted,
251 GrMipMapped mipMapped,
252 GrProtected isProtected,
253 const void* data, size_t dataSize) {
254 // TODO
255 return nullptr;
256}
257
Jim Van Verth9145f782020-04-28 12:01:12 -0400258static int get_surface_sample_cnt(GrSurface* surf) {
259 if (const GrRenderTarget* rt = surf->asRenderTarget()) {
260 return rt->numSamples();
261 }
262 return 0;
263}
264
265bool GrD3DGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
266 const SkIPoint& dstPoint) {
267
268 if (src->isProtected() && !dst->isProtected()) {
269 SkDebugf("Can't copy from protected memory to non-protected");
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400270 return false;
271 }
Jim Van Verth9145f782020-04-28 12:01:12 -0400272
273 int dstSampleCnt = get_surface_sample_cnt(dst);
274 int srcSampleCnt = get_surface_sample_cnt(src);
275
276 GrD3DTextureResource* dstTexResource;
277 GrD3DTextureResource* srcTexResource;
278 GrRenderTarget* dstRT = dst->asRenderTarget();
279 if (dstRT) {
280 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(dstRT);
281 dstTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
282 } else {
283 SkASSERT(dst->asTexture());
284 dstTexResource = static_cast<GrD3DTexture*>(dst->asTexture());
285 }
286 GrRenderTarget* srcRT = src->asRenderTarget();
287 if (srcRT) {
288 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(srcRT);
289 srcTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
290 } else {
291 SkASSERT(src->asTexture());
292 srcTexResource = static_cast<GrD3DTexture*>(src->asTexture());
293 }
294
295 DXGI_FORMAT dstFormat = dstTexResource->dxgiFormat();
296 DXGI_FORMAT srcFormat = srcTexResource->dxgiFormat();
297
298 if (this->d3dCaps().canCopyAsResolve(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
299 this->copySurfaceAsResolve(dst, src, srcRect, dstPoint);
300 return true;
301 }
302
303 if (this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
304 this->copySurfaceAsCopyTexture(dst, src, dstTexResource, srcTexResource, srcRect, dstPoint);
305 return true;
306 }
307
308 return false;
309}
310
311void GrD3DGpu::copySurfaceAsCopyTexture(GrSurface* dst, GrSurface* src,
312 GrD3DTextureResource* dstResource,
313 GrD3DTextureResource* srcResource,
314 const SkIRect& srcRect, const SkIPoint& dstPoint) {
315#ifdef SK_DEBUG
316 int dstSampleCnt = get_surface_sample_cnt(dst);
317 int srcSampleCnt = get_surface_sample_cnt(src);
318 DXGI_FORMAT dstFormat = dstResource->dxgiFormat();
319 DXGI_FORMAT srcFormat;
320 SkAssertResult(dst->backendFormat().asDxgiFormat(&srcFormat));
321 SkASSERT(this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt));
322#endif
323 if (src->isProtected() && !dst->isProtected()) {
324 SkDebugf("Can't copy from protected memory to non-protected");
325 return;
326 }
327
328 dstResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
329 srcResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
330
331 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
332 dstLocation.pResource = dstResource->d3dResource();
333 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
334 dstLocation.SubresourceIndex = 0;
335
336 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
337 srcLocation.pResource = srcResource->d3dResource();
338 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
339 srcLocation.SubresourceIndex = 0;
340
341 D3D12_BOX srcBox = {};
342 srcBox.left = srcRect.fLeft;
343 srcBox.top = srcRect.fTop;
344 srcBox.right = srcRect.fRight;
345 srcBox.bottom = srcRect.fBottom;
346 srcBox.front = 0;
347 srcBox.back = 1;
348 // TODO: use copyResource if copying full resource and sizes match
349 fCurrentDirectCommandList->copyTextureRegion(dstResource->resource(),
350 &dstLocation,
351 dstPoint.fX, dstPoint.fY,
352 srcResource->resource(),
353 &srcLocation,
354 &srcBox);
355
356 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
357 srcRect.width(), srcRect.height());
358 // The rect is already in device space so we pass in kTopLeft so no flip is done.
359 this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
360}
361
362void GrD3DGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
363 const SkIPoint& dstPoint) {
364 // TODO
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400365}
366
Jim Van Verthba7f2292020-04-21 08:56:47 -0400367bool GrD3DGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
368 GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
369 size_t rowBytes) {
370 SkASSERT(surface);
371
372 if (surfaceColorType != dstColorType) {
373 return false;
374 }
375
376 // Set up src location and box
Jim Van Verthc12aad92020-04-24 16:19:01 -0400377 GrD3DTextureResource* texResource = nullptr;
378 GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(surface->asRenderTarget());
379 if (rt) {
380 texResource = rt;
381 } else {
382 texResource = static_cast<GrD3DTexture*>(surface->asTexture());
383 }
384
385 if (!texResource) {
Jim Van Verthba7f2292020-04-21 08:56:47 -0400386 return false;
387 }
Jim Van Verthc12aad92020-04-24 16:19:01 -0400388
Jim Van Verthba7f2292020-04-21 08:56:47 -0400389 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
Jim Van Verthc12aad92020-04-24 16:19:01 -0400390 srcLocation.pResource = texResource->d3dResource();
Jim Van Verthba7f2292020-04-21 08:56:47 -0400391 SkASSERT(srcLocation.pResource);
392 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
393 srcLocation.SubresourceIndex = 0;
394
395 D3D12_BOX srcBox = {};
396 srcBox.left = left;
397 srcBox.top = top;
398 srcBox.right = left + width;
399 srcBox.bottom = top + height;
400 srcBox.front = 0;
401 srcBox.back = 1;
402
403 // Set up dst location and create transfer buffer
404 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
405 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400406 UINT64 transferTotalBytes;
407 const UINT64 baseOffset = 0;
408 D3D12_RESOURCE_DESC desc = srcLocation.pResource->GetDesc();
409 fDevice->GetCopyableFootprints(&desc, 0, 1, baseOffset, &dstLocation.PlacedFootprint,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400410 nullptr, nullptr, &transferTotalBytes);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400411 SkASSERT(transferTotalBytes);
Jim Van Verthfdd36852020-04-21 16:29:44 -0400412 size_t bpp = GrColorTypeBytesPerPixel(dstColorType);
Jim Van Verthc12aad92020-04-24 16:19:01 -0400413 if (this->d3dCaps().bytesPerPixel(texResource->dxgiFormat()) != bpp) {
Jim Van Verthfdd36852020-04-21 16:29:44 -0400414 return false;
415 }
416 size_t tightRowBytes = bpp * width;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400417
418 // TODO: implement some way of reusing buffers instead of making a new one every time.
419 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(transferTotalBytes,
420 GrGpuBufferType::kXferGpuToCpu,
421 kDynamic_GrAccessPattern);
422 GrD3DBuffer* d3dBuf = static_cast<GrD3DBuffer*>(transferBuffer.get());
423 dstLocation.pResource = d3dBuf->d3dResource();
424
425 // Need to change the resource state to COPY_SOURCE in order to download from it
Jim Van Verthc12aad92020-04-24 16:19:01 -0400426 texResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400427
428 fCurrentDirectCommandList->copyTextureRegion(d3dBuf->resource(), &dstLocation, 0, 0,
Jim Van Verthc12aad92020-04-24 16:19:01 -0400429 texResource->resource(), &srcLocation, &srcBox);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400430 this->submitDirectCommandList(SyncQueue::kForce);
431
432 const void* mappedMemory = transferBuffer->map();
433
434 SkRectMemcpy(buffer, rowBytes, mappedMemory, dstLocation.PlacedFootprint.Footprint.RowPitch,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400435 tightRowBytes, height);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400436
437 transferBuffer->unmap();
438
439 return true;
440}
441
442bool GrD3DGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
443 GrColorType surfaceColorType, GrColorType srcColorType,
444 const GrMipLevel texels[], int mipLevelCount,
445 bool prepForTexSampling) {
446 GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
447 if (!d3dTex) {
448 return false;
449 }
450
451 // Make sure we have at least the base level
452 if (!mipLevelCount || !texels[0].fPixels) {
453 return false;
454 }
455
456 SkASSERT(!GrDxgiFormatIsCompressed(d3dTex->dxgiFormat()));
457 bool success = false;
458
459 // Need to change the resource state to COPY_DEST in order to upload to it
460 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
461
462 SkASSERT(mipLevelCount <= d3dTex->texturePriv().maxMipMapLevel() + 1);
463 success = this->uploadToTexture(d3dTex, left, top, width, height, srcColorType, texels,
464 mipLevelCount);
465
466 if (prepForTexSampling) {
467 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
468 }
469
470 return success;
471}
472
473bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex, int left, int top, int width, int height,
474 GrColorType colorType, const GrMipLevel* texels, int mipLevelCount) {
475 SkASSERT(this->caps()->isFormatTexturable(tex->backendFormat()));
476 // The assumption is either that we have no mipmaps, or that our rect is the entire texture
477 SkASSERT(1 == mipLevelCount ||
478 (0 == left && 0 == top && width == tex->width() && height == tex->height()));
479
480 // We assume that if the texture has mip levels, we either upload to all the levels or just the
481 // first.
482 SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
483
484 if (width == 0 || height == 0) {
485 return false;
486 }
487
488 SkASSERT(this->d3dCaps().surfaceSupportsWritePixels(tex));
489 SkASSERT(this->d3dCaps().areColorTypeAndFormatCompatible(colorType, tex->backendFormat()));
490
491 ID3D12Resource* d3dResource = tex->d3dResource();
492 SkASSERT(d3dResource);
493 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
494 // Either upload only the first miplevel or all miplevels
495 SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
496
497 if (1 == mipLevelCount && !texels[0].fPixels) {
498 return true; // no data to upload
499 }
500
501 for (int i = 0; i < mipLevelCount; ++i) {
502 // We do not allow any gaps in the mip data
503 if (!texels[i].fPixels) {
504 return false;
505 }
506 }
507
508 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400509 UINT64 combinedBufferSize;
510 // We reset the width and height in the description to match our subrectangle size
511 // so we don't end up allocating more space than we need.
512 desc.Width = width;
513 desc.Height = height;
514 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
Jim Van Verthfdd36852020-04-21 16:29:44 -0400515 nullptr, nullptr, &combinedBufferSize);
516 size_t bpp = GrColorTypeBytesPerPixel(colorType);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400517 SkASSERT(combinedBufferSize);
518
519 // TODO: do this until we have slices of buttery buffers
520 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(combinedBufferSize,
521 GrGpuBufferType::kXferCpuToGpu,
522 kDynamic_GrAccessPattern);
523 if (!transferBuffer) {
524 return false;
525 }
526 char* bufferData = (char*)transferBuffer->map();
527
528 int currentWidth = width;
529 int currentHeight = height;
530 int layerHeight = tex->height();
531
532 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
533 if (texels[currentMipLevel].fPixels) {
534 SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
535
Jim Van Verthfdd36852020-04-21 16:29:44 -0400536 const size_t trimRowBytes = currentWidth * bpp;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400537 const size_t srcRowBytes = texels[currentMipLevel].fRowBytes;
538
539 char* dst = bufferData + placedFootprints[currentMipLevel].Offset;
540
541 // copy data into the buffer, skipping any trailing bytes
Jim Van Verthba7f2292020-04-21 08:56:47 -0400542 const char* src = (const char*)texels[currentMipLevel].fPixels;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400543 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
544 src, srcRowBytes, trimRowBytes, currentHeight);
545 }
546 currentWidth = std::max(1, currentWidth / 2);
547 currentHeight = std::max(1, currentHeight / 2);
548 layerHeight = currentHeight;
549 }
550
551 transferBuffer->unmap();
552
553 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get());
554 fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, tex, mipLevelCount,
555 placedFootprints.get(), left, top);
556
557 if (mipLevelCount < (int)desc.MipLevels) {
558 tex->texturePriv().markMipMapsDirty();
559 }
560
561 return true;
562}
563
Jim Van Verth280d4f72020-05-04 10:04:24 -0400564void GrD3DGpu::clear(const GrFixedClip& clip, const SkPMColor4f& color, GrRenderTarget* rt) {
565 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(rt);
566
567 d3dRT->setResourceState(this, D3D12_RESOURCE_STATE_RENDER_TARGET);
568
569 fCurrentDirectCommandList->clearRenderTargetView(d3dRT, color, clip);
570}
571
Jim Van Verth9145f782020-04-28 12:01:12 -0400572static bool check_resource_info(const GrD3DTextureResourceInfo& info) {
573 if (!info.fResource.get()) {
574 return false;
575 }
576 return true;
577}
578
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400579static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
580 if (!caps.isFormatTexturable(info.fFormat)) {
581 return false;
582 }
583 return true;
584}
585
586static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
587 int sampleCnt) {
588 if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
589 return false;
590 }
591 return true;
592}
593
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400594sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
595 GrWrapOwnership,
596 GrWrapCacheable wrapType,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400597 GrIOType ioType) {
598 GrD3DTextureResourceInfo textureInfo;
599 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
600 return nullptr;
601 }
602
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400603 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400604 return nullptr;
605 }
606
607 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
608 return nullptr;
609 }
610
611 // TODO: support protected context
612 if (tex.isProtected()) {
613 return nullptr;
614 }
615
616 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
617 SkASSERT(state);
618 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
619 std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500620}
621
622sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400623 GrWrapOwnership,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500624 GrWrapCacheable wrapType) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400625 GrD3DTextureResourceInfo textureInfo;
626 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
627 return nullptr;
628 }
629
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400630 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400631 return nullptr;
632 }
633
634 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
635 return nullptr;
636 }
637
638 // TODO: support protected context
639 if (tex.isProtected()) {
640 return nullptr;
641 }
642
643 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
644 SkASSERT(state);
645 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, kRead_GrIOType,
646 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500647}
648
649sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
650 int sampleCnt,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500651 GrWrapOwnership ownership,
652 GrWrapCacheable cacheable) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400653 GrD3DTextureResourceInfo textureInfo;
654 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
655 return nullptr;
656 }
657
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400658 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400659 return nullptr;
660 }
661
662 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
663 return nullptr;
664 }
665 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
666 return nullptr;
667 }
668
669 // TODO: support protected context
670 if (tex.isProtected()) {
671 return nullptr;
672 }
673
674 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
675
676 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
677 SkASSERT(state);
678
679 return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
680 sampleCnt, cacheable,
681 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500682}
683
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400684sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400685 // Currently the Direct3D backend does not support wrapping of msaa render targets directly. In
686 // general this is not an issue since swapchain images in D3D are never multisampled. Thus if
687 // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
688 // creating and owning the MSAA images.
689 if (rt.sampleCnt() > 1) {
690 return nullptr;
691 }
692
693 GrD3DTextureResourceInfo info;
694 if (!rt.getD3DTextureResourceInfo(&info)) {
695 return nullptr;
696 }
697
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400698 if (!check_resource_info(info)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400699 return nullptr;
700 }
701
702 if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
703 return nullptr;
704 }
705
706 // TODO: support protected context
707 if (rt.isProtected()) {
708 return nullptr;
709 }
710
711 sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
712
713 sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
714 this, rt.dimensions(), 1, info, std::move(state));
715
716 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
717 SkASSERT(!rt.stencilBits());
718 if (tgt) {
719 SkASSERT(tgt->canAttemptStencilAttachment());
720 }
721
722 return std::move(tgt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500723}
724
725sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400726 int sampleCnt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400727
728 GrD3DTextureResourceInfo textureInfo;
729 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
730 return nullptr;
731 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400732 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400733 return nullptr;
734 }
735
736 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
737 return nullptr;
738 }
739
740 // TODO: support protected context
741 if (tex.isProtected()) {
742 return nullptr;
743 }
744
745 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
746 if (!sampleCnt) {
747 return nullptr;
748 }
749
750 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
751 SkASSERT(state);
752
753 return GrD3DRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt,
754 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500755}
756
757sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
Jim Van Verthd6ad4802020-04-03 14:59:20 -0400758 GrAccessPattern accessPattern, const void* data) {
759 sk_sp<GrD3DBuffer> buffer = GrD3DBuffer::Make(this, sizeInBytes, type, accessPattern);
760 if (data && buffer) {
761 buffer->updateData(data, sizeInBytes);
762 }
763
764 return std::move(buffer);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500765}
766
767GrStencilAttachment* GrD3DGpu::createStencilAttachmentForRenderTarget(
768 const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
Jim Van Verth4f51f472020-04-13 11:02:21 -0400769 SkASSERT(numStencilSamples == rt->numSamples() || this->caps()->mixedSamplesSupport());
770 SkASSERT(width >= rt->width());
771 SkASSERT(height >= rt->height());
772
773 const GrD3DCaps::StencilFormat& sFmt = this->d3dCaps().preferredStencilFormat();
774
775 GrD3DStencilAttachment* stencil(GrD3DStencilAttachment::Make(this,
776 width,
777 height,
778 numStencilSamples,
779 sFmt));
780 fStats.incStencilAttachmentCreates();
781 return stencil;
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500782}
783
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400784bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
785 SkISize dimensions,
786 GrTexturable texturable,
787 GrRenderable renderable,
788 GrMipMapped mipMapped,
789 GrD3DTextureResourceInfo* info,
790 GrProtected isProtected,
Greg Danielc1ad77c2020-05-06 11:40:03 -0400791 sk_sp<GrRefCntedCallback> finishedCallback,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400792 const BackendTextureData* data) {
793 SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
794 if (texturable == GrTexturable::kNo) {
795 SkASSERT(!data && mipMapped == GrMipMapped::kNo);
796 }
797
798 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
799 return false;
800 }
801
802 if (texturable == GrTexturable::kYes && !this->d3dCaps().isFormatTexturable(dxgiFormat)) {
803 return false;
804 }
805
806 if (renderable == GrRenderable::kYes && !this->d3dCaps().isFormatRenderable(dxgiFormat, 1)) {
807 return false;
808 }
809
810 int numMipLevels = 1;
811 if (mipMapped == GrMipMapped::kYes) {
812 numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
813 }
814
815 // create the texture
816 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
817 if (renderable == GrRenderable::kYes) {
818 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
819 }
820
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400821 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400822 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
823 resourceDesc.Alignment = 0; // use default alignment
824 resourceDesc.Width = dimensions.fWidth;
825 resourceDesc.Height = dimensions.fHeight;
826 resourceDesc.DepthOrArraySize = 1;
827 resourceDesc.MipLevels = numMipLevels;
828 resourceDesc.Format = dxgiFormat;
829 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400830 // quality levels are only supported for tiled resources so ignore for now
831 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400832 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
833 resourceDesc.Flags = usageFlags;
834
Jim Van Verth280d4f72020-05-04 10:04:24 -0400835 D3D12_CLEAR_VALUE* clearValuePtr = nullptr;
836 D3D12_CLEAR_VALUE clearValue = {};
837 if (renderable == GrRenderable::kYes) {
838 clearValue.Format = dxgiFormat;
839 // Assume transparent black
840 clearValue.Color[0] = 0;
841 clearValue.Color[1] = 0;
842 clearValue.Color[2] = 0;
843 clearValue.Color[3] = 0;
844 clearValuePtr = &clearValue;
845 }
846
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400847 D3D12_RESOURCE_STATES initialState =
848 (renderable == GrRenderable::kYes) && !data ? D3D12_RESOURCE_STATE_RENDER_TARGET :
849 D3D12_RESOURCE_STATE_COPY_DEST;
850 if (!GrD3DTextureResource::InitTextureResourceInfo(this, resourceDesc, initialState,
Jim Van Verth280d4f72020-05-04 10:04:24 -0400851 isProtected, clearValuePtr, info)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400852 SkDebugf("Failed to init texture resource info\n");
853 return false;
854 }
855
856 if (!data) {
857 return true;
858 }
859
Greg Danielc1ad77c2020-05-06 11:40:03 -0400860 // TODO: upload the data and handle finished callback
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400861
862 return true;
863}
864
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500865GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400866 const GrBackendFormat& format,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400867 GrRenderable renderable,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400868 GrMipMapped mipMapped,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400869 GrProtected isProtected,
Greg Danielc1ad77c2020-05-06 11:40:03 -0400870 sk_sp<GrRefCntedCallback> finishedCallback,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400871 const BackendTextureData* data) {
872 this->handleDirtyContext();
873
874 const GrD3DCaps& caps = this->d3dCaps();
875
876 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
877 return {};
878 }
879
880 DXGI_FORMAT dxgiFormat;
881 if (!format.asDxgiFormat(&dxgiFormat)) {
882 return {};
883 }
884
885 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
886 if (!caps.isFormatTexturable(dxgiFormat)) {
887 return {};
888 }
889
890 GrD3DTextureResourceInfo info;
891 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
892 renderable, mipMapped,
Greg Danielc1ad77c2020-05-06 11:40:03 -0400893 &info, isProtected,
894 std::move(finishedCallback), data)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400895 return {};
896 }
897
898 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500899}
900
Greg Danielc1ad77c2020-05-06 11:40:03 -0400901GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(
902 SkISize dimensions, const GrBackendFormat& format, GrMipMapped mipMapped,
903 GrProtected isProtected, sk_sp<GrRefCntedCallback> finishedCallback,
904 const BackendTextureData* data) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400905 this->handleDirtyContext();
906
907 const GrD3DCaps& caps = this->d3dCaps();
908
909 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
910 return {};
911 }
912
913 DXGI_FORMAT dxgiFormat;
914 if (!format.asDxgiFormat(&dxgiFormat)) {
915 return {};
916 }
917
918 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
919 if (!caps.isFormatTexturable(dxgiFormat)) {
920 return {};
921 }
922
923 GrD3DTextureResourceInfo info;
924 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
925 GrRenderable::kNo, mipMapped,
Greg Danielc1ad77c2020-05-06 11:40:03 -0400926 &info, isProtected,
927 std::move(finishedCallback), data)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400928 return {};
929 }
930
931 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500932}
933
934void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400935 SkASSERT(GrBackendApi::kDirect3D == tex.fBackend);
936 // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500937}
938
Robert Phillips979b2232020-02-20 10:47:29 -0500939bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
940 return false;
941}
942
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500943#if GR_TEST_UTILS
944bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400945 SkASSERT(GrBackendApi::kDirect3D == tex.backend());
946
947 GrD3DTextureResourceInfo info;
948 if (!tex.getD3DTextureResourceInfo(&info)) {
949 return false;
950 }
951 ID3D12Resource* textureResource = info.fResource.get();
952 if (!textureResource) {
953 return false;
954 }
955 return !(textureResource->GetDesc().Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500956}
957
958GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(int w, int h,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400959 GrColorType colorType) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400960 this->handleDirtyContext();
961
962 if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400963 return {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400964 }
965
966 DXGI_FORMAT dxgiFormat = this->d3dCaps().getFormatFromColorType(colorType);
967
968 GrD3DTextureResourceInfo info;
969 if (!this->createTextureResourceForBackendSurface(dxgiFormat, { w, h }, GrTexturable::kNo,
970 GrRenderable::kYes, GrMipMapped::kNo,
Greg Danielc1ad77c2020-05-06 11:40:03 -0400971 &info, GrProtected::kNo, nullptr, nullptr)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400972 return {};
973 }
974
975 return GrBackendRenderTarget(w, h, 1, info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500976}
977
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400978void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
979 SkASSERT(GrBackendApi::kDirect3D == rt.backend());
980
981 GrD3DTextureResourceInfo info;
982 if (rt.getD3DTextureResourceInfo(&info)) {
983 this->testingOnly_flushGpuAndSync();
984 // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
985 // is deleted.
986 }
987}
988
989void GrD3DGpu::testingOnly_flushGpuAndSync() {
Jim Van Verthc632aa62020-04-17 16:58:20 -0400990 SkAssertResult(this->submitDirectCommandList(SyncQueue::kForce));
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400991}
Jim Van Verthc632aa62020-04-17 16:58:20 -0400992
Jim Van Verth9b5e16c2020-04-20 10:45:52 -0400993void GrD3DGpu::testingOnly_startCapture() {
994 if (fGraphicsAnalysis) {
995 fGraphicsAnalysis->BeginCapture();
996 }
997}
998
999void GrD3DGpu::testingOnly_endCapture() {
1000 if (fGraphicsAnalysis) {
1001 fGraphicsAnalysis->EndCapture();
1002 }
1003}
1004#endif
1005
Jim Van Verthc632aa62020-04-17 16:58:20 -04001006///////////////////////////////////////////////////////////////////////////////
1007
Greg Daniela5a6b322020-04-23 12:52:27 -04001008void GrD3DGpu::addResourceBarriers(sk_sp<GrManagedResource> resource,
Jim Van Verthc632aa62020-04-17 16:58:20 -04001009 int numBarriers,
1010 D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
1011 SkASSERT(fCurrentDirectCommandList);
1012 SkASSERT(resource);
1013
Greg Daniela5a6b322020-04-23 12:52:27 -04001014 fCurrentDirectCommandList->resourceBarrier(std::move(resource), numBarriers, barriers);
Jim Van Verthc632aa62020-04-17 16:58:20 -04001015}
1016
1017bool GrD3DGpu::onSubmitToGpu(bool syncCpu) {
1018 if (syncCpu) {
1019 return this->submitDirectCommandList(SyncQueue::kForce);
1020 } else {
1021 return this->submitDirectCommandList(SyncQueue::kSkip);
1022 }
1023}