blob: b1468f96ff0618384d5a610a0bc61f06dae403b9 [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 }
Jim Van Verthf2788862020-06-03 17:33:12 -040093
94 fResourceProvider.destroyResources();
Greg Daniel83ed2132020-03-24 13:15:33 -040095}
Greg Daniel31a7b072020-02-26 15:31:49 -050096
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050097GrOpsRenderPass* GrD3DGpu::getOpsRenderPass(
Robert Phillips96f22372020-05-20 12:31:18 -040098 GrRenderTarget* rt, GrStencilAttachment*,
99 GrSurfaceOrigin origin, const SkIRect& bounds,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500100 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
Greg Daniel31a7b072020-02-26 15:31:49 -0500101 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500102 const SkTArray<GrSurfaceProxy*, true>& sampledProxies) {
Greg Daniel31a7b072020-02-26 15:31:49 -0500103 if (!fCachedOpsRenderPass) {
104 fCachedOpsRenderPass.reset(new GrD3DOpsRenderPass(this));
105 }
106
107 if (!fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies)) {
108 return nullptr;
109 }
110 return fCachedOpsRenderPass.get();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500111}
112
Jim Van Verthc632aa62020-04-17 16:58:20 -0400113bool GrD3DGpu::submitDirectCommandList(SyncQueue sync) {
Greg Daniel83ed2132020-03-24 13:15:33 -0400114 SkASSERT(fCurrentDirectCommandList);
115
Jim Van Verth3eadce22020-06-01 11:34:49 -0400116 fResourceProvider.prepForSubmit();
117
Jim Van Verthc632aa62020-04-17 16:58:20 -0400118 GrD3DDirectCommandList::SubmitResult result = fCurrentDirectCommandList->submit(fQueue.get());
119 if (result == GrD3DDirectCommandList::SubmitResult::kFailure) {
120 return false;
121 } else if (result == GrD3DDirectCommandList::SubmitResult::kNoWork) {
122 if (sync == SyncQueue::kForce) {
123 this->waitForQueueCompletion();
Jim Van Verth682a2f42020-05-13 16:54:09 -0400124 this->checkForFinishedCommandLists();
Jim Van Verthc632aa62020-04-17 16:58:20 -0400125 }
126 return true;
127 }
Greg Daniel83ed2132020-03-24 13:15:33 -0400128
129 new (fOutstandingCommandLists.push_back()) OutstandingCommandList(
130 std::move(fCurrentDirectCommandList), ++fCurrentFenceValue);
131
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400132 SkDEBUGCODE(HRESULT hr = ) fQueue->Signal(fFence.get(), fCurrentFenceValue);
Greg Daniel83ed2132020-03-24 13:15:33 -0400133 SkASSERT(SUCCEEDED(hr));
134
Jim Van Verthc632aa62020-04-17 16:58:20 -0400135 if (sync == SyncQueue::kForce) {
136 this->waitForQueueCompletion();
137 }
138
Greg Daniel83ed2132020-03-24 13:15:33 -0400139 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
140
141 // This should be done after we have a new command list in case the freeing of any resources
142 // held by a finished command list causes us send a new command to the gpu (like changing the
143 // resource state.
144 this->checkForFinishedCommandLists();
145
146 SkASSERT(fCurrentDirectCommandList);
Jim Van Verthc632aa62020-04-17 16:58:20 -0400147 return true;
Greg Daniel83ed2132020-03-24 13:15:33 -0400148}
149
150void GrD3DGpu::checkForFinishedCommandLists() {
151 uint64_t currentFenceValue = fFence->GetCompletedValue();
152
153 // Iterate over all the outstanding command lists to see if any have finished. The commands
154 // lists are in order from oldest to newest, so we start at the front to check if their fence
155 // value is less than the last signaled value. If so we pop it off and move onto the next.
156 // Repeat till we find a command list that has not finished yet (and all others afterwards are
157 // also guaranteed to not have finished).
158 SkDeque::F2BIter iter(fOutstandingCommandLists);
159 const OutstandingCommandList* curList = (const OutstandingCommandList*)iter.next();
160 while (curList && curList->fFenceValue <= currentFenceValue) {
161 curList = (const OutstandingCommandList*)iter.next();
162 OutstandingCommandList* front = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel7a5f1fa2020-03-24 14:50:19 -0400163 fResourceProvider.recycleDirectCommandList(std::move(front->fCommandList));
Greg Daniel83ed2132020-03-24 13:15:33 -0400164 // Since we used placement new we are responsible for calling the destructor manually.
165 front->~OutstandingCommandList();
166 fOutstandingCommandLists.pop_front();
167 }
168}
169
Jim Van Verthc632aa62020-04-17 16:58:20 -0400170void GrD3DGpu::waitForQueueCompletion() {
171 if (fFence->GetCompletedValue() < fCurrentFenceValue) {
172 HANDLE fenceEvent;
173 fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
174 SkASSERT(fenceEvent);
175 SkDEBUGCODE(HRESULT hr = ) fFence->SetEventOnCompletion(fCurrentFenceValue, fenceEvent);
176 SkASSERT(SUCCEEDED(hr));
177 WaitForSingleObject(fenceEvent, INFINITE);
178 CloseHandle(fenceEvent);
179 }
180}
181
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500182void GrD3DGpu::submit(GrOpsRenderPass* renderPass) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400183 SkASSERT(fCachedOpsRenderPass.get() == renderPass);
184
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500185 // TODO: actually submit something here
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400186 fCachedOpsRenderPass.reset();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500187}
188
189void GrD3DGpu::querySampleLocations(GrRenderTarget* rt, SkTArray<SkPoint>* sampleLocations) {
190 // TODO
191}
192
193sk_sp<GrTexture> GrD3DGpu::onCreateTexture(SkISize dimensions,
194 const GrBackendFormat& format,
195 GrRenderable renderable,
196 int renderTargetSampleCnt,
197 SkBudgeted budgeted,
198 GrProtected isProtected,
199 int mipLevelCount,
200 uint32_t levelClearMask) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400201 DXGI_FORMAT dxgiFormat;
202 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
203 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
204
205 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
206
207 if (renderable == GrRenderable::kYes) {
208 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
209 }
210
211 // This desc refers to the texture that will be read by the client. Thus even if msaa is
212 // requested, this describes the resolved texture. Therefore we always have samples set
213 // to 1.
214 SkASSERT(mipLevelCount > 0);
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400215 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400216 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
217 // TODO: will use 4MB alignment for MSAA textures and 64KB for everything else
218 // might want to manually set alignment to 4KB for smaller textures
219 resourceDesc.Alignment = 0;
220 resourceDesc.Width = dimensions.fWidth;
221 resourceDesc.Height = dimensions.fHeight;
222 resourceDesc.DepthOrArraySize = 1;
223 resourceDesc.MipLevels = mipLevelCount;
224 resourceDesc.Format = dxgiFormat;
225 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400226 // quality levels are only supported for tiled resources so ignore for now
227 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400228 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400229 resourceDesc.Flags = usageFlags;
230
231 GrMipMapsStatus mipMapsStatus =
232 mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
233
234 sk_sp<GrD3DTexture> tex;
235 if (renderable == GrRenderable::kYes) {
236 tex = GrD3DTextureRenderTarget::MakeNewTextureRenderTarget(
237 this, budgeted, dimensions, renderTargetSampleCnt, resourceDesc, isProtected,
238 mipMapsStatus);
239 } else {
240 tex = GrD3DTexture::MakeNewTexture(this, budgeted, dimensions, resourceDesc, isProtected,
241 mipMapsStatus);
242 }
243
244 if (!tex) {
245 return nullptr;
246 }
247
248 if (levelClearMask) {
249 // TODO
250 }
251 return std::move(tex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500252}
253
254sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
255 const GrBackendFormat& format,
256 SkBudgeted budgeted,
257 GrMipMapped mipMapped,
258 GrProtected isProtected,
259 const void* data, size_t dataSize) {
260 // TODO
261 return nullptr;
262}
263
Jim Van Verth9145f782020-04-28 12:01:12 -0400264static int get_surface_sample_cnt(GrSurface* surf) {
265 if (const GrRenderTarget* rt = surf->asRenderTarget()) {
266 return rt->numSamples();
267 }
268 return 0;
269}
270
271bool GrD3DGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
272 const SkIPoint& dstPoint) {
273
274 if (src->isProtected() && !dst->isProtected()) {
275 SkDebugf("Can't copy from protected memory to non-protected");
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400276 return false;
277 }
Jim Van Verth9145f782020-04-28 12:01:12 -0400278
279 int dstSampleCnt = get_surface_sample_cnt(dst);
280 int srcSampleCnt = get_surface_sample_cnt(src);
281
282 GrD3DTextureResource* dstTexResource;
283 GrD3DTextureResource* srcTexResource;
284 GrRenderTarget* dstRT = dst->asRenderTarget();
285 if (dstRT) {
286 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(dstRT);
287 dstTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
288 } else {
289 SkASSERT(dst->asTexture());
290 dstTexResource = static_cast<GrD3DTexture*>(dst->asTexture());
291 }
292 GrRenderTarget* srcRT = src->asRenderTarget();
293 if (srcRT) {
294 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(srcRT);
295 srcTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
296 } else {
297 SkASSERT(src->asTexture());
298 srcTexResource = static_cast<GrD3DTexture*>(src->asTexture());
299 }
300
301 DXGI_FORMAT dstFormat = dstTexResource->dxgiFormat();
302 DXGI_FORMAT srcFormat = srcTexResource->dxgiFormat();
303
304 if (this->d3dCaps().canCopyAsResolve(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
305 this->copySurfaceAsResolve(dst, src, srcRect, dstPoint);
306 return true;
307 }
308
309 if (this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
310 this->copySurfaceAsCopyTexture(dst, src, dstTexResource, srcTexResource, srcRect, dstPoint);
311 return true;
312 }
313
314 return false;
315}
316
317void GrD3DGpu::copySurfaceAsCopyTexture(GrSurface* dst, GrSurface* src,
318 GrD3DTextureResource* dstResource,
319 GrD3DTextureResource* srcResource,
320 const SkIRect& srcRect, const SkIPoint& dstPoint) {
321#ifdef SK_DEBUG
322 int dstSampleCnt = get_surface_sample_cnt(dst);
323 int srcSampleCnt = get_surface_sample_cnt(src);
324 DXGI_FORMAT dstFormat = dstResource->dxgiFormat();
325 DXGI_FORMAT srcFormat;
326 SkAssertResult(dst->backendFormat().asDxgiFormat(&srcFormat));
327 SkASSERT(this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt));
328#endif
329 if (src->isProtected() && !dst->isProtected()) {
330 SkDebugf("Can't copy from protected memory to non-protected");
331 return;
332 }
333
334 dstResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
335 srcResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
336
337 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
338 dstLocation.pResource = dstResource->d3dResource();
339 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
340 dstLocation.SubresourceIndex = 0;
341
342 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
343 srcLocation.pResource = srcResource->d3dResource();
344 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
345 srcLocation.SubresourceIndex = 0;
346
347 D3D12_BOX srcBox = {};
348 srcBox.left = srcRect.fLeft;
349 srcBox.top = srcRect.fTop;
350 srcBox.right = srcRect.fRight;
351 srcBox.bottom = srcRect.fBottom;
352 srcBox.front = 0;
353 srcBox.back = 1;
354 // TODO: use copyResource if copying full resource and sizes match
355 fCurrentDirectCommandList->copyTextureRegion(dstResource->resource(),
356 &dstLocation,
357 dstPoint.fX, dstPoint.fY,
358 srcResource->resource(),
359 &srcLocation,
360 &srcBox);
361
362 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
363 srcRect.width(), srcRect.height());
364 // The rect is already in device space so we pass in kTopLeft so no flip is done.
365 this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
366}
367
368void GrD3DGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
369 const SkIPoint& dstPoint) {
370 // TODO
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400371}
372
Jim Van Verthba7f2292020-04-21 08:56:47 -0400373bool GrD3DGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
374 GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
375 size_t rowBytes) {
376 SkASSERT(surface);
377
378 if (surfaceColorType != dstColorType) {
379 return false;
380 }
381
382 // Set up src location and box
Jim Van Verthc12aad92020-04-24 16:19:01 -0400383 GrD3DTextureResource* texResource = nullptr;
384 GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(surface->asRenderTarget());
385 if (rt) {
386 texResource = rt;
387 } else {
388 texResource = static_cast<GrD3DTexture*>(surface->asTexture());
389 }
390
391 if (!texResource) {
Jim Van Verthba7f2292020-04-21 08:56:47 -0400392 return false;
393 }
Jim Van Verthc12aad92020-04-24 16:19:01 -0400394
Jim Van Verthba7f2292020-04-21 08:56:47 -0400395 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
Jim Van Verthc12aad92020-04-24 16:19:01 -0400396 srcLocation.pResource = texResource->d3dResource();
Jim Van Verthba7f2292020-04-21 08:56:47 -0400397 SkASSERT(srcLocation.pResource);
398 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
399 srcLocation.SubresourceIndex = 0;
400
401 D3D12_BOX srcBox = {};
402 srcBox.left = left;
403 srcBox.top = top;
404 srcBox.right = left + width;
405 srcBox.bottom = top + height;
406 srcBox.front = 0;
407 srcBox.back = 1;
408
409 // Set up dst location and create transfer buffer
410 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
411 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400412 UINT64 transferTotalBytes;
413 const UINT64 baseOffset = 0;
414 D3D12_RESOURCE_DESC desc = srcLocation.pResource->GetDesc();
415 fDevice->GetCopyableFootprints(&desc, 0, 1, baseOffset, &dstLocation.PlacedFootprint,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400416 nullptr, nullptr, &transferTotalBytes);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400417 SkASSERT(transferTotalBytes);
Jim Van Verthfdd36852020-04-21 16:29:44 -0400418 size_t bpp = GrColorTypeBytesPerPixel(dstColorType);
Jim Van Verthc12aad92020-04-24 16:19:01 -0400419 if (this->d3dCaps().bytesPerPixel(texResource->dxgiFormat()) != bpp) {
Jim Van Verthfdd36852020-04-21 16:29:44 -0400420 return false;
421 }
422 size_t tightRowBytes = bpp * width;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400423
424 // TODO: implement some way of reusing buffers instead of making a new one every time.
425 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(transferTotalBytes,
426 GrGpuBufferType::kXferGpuToCpu,
427 kDynamic_GrAccessPattern);
428 GrD3DBuffer* d3dBuf = static_cast<GrD3DBuffer*>(transferBuffer.get());
429 dstLocation.pResource = d3dBuf->d3dResource();
430
431 // Need to change the resource state to COPY_SOURCE in order to download from it
Jim Van Verthc12aad92020-04-24 16:19:01 -0400432 texResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400433
434 fCurrentDirectCommandList->copyTextureRegion(d3dBuf->resource(), &dstLocation, 0, 0,
Jim Van Verthc12aad92020-04-24 16:19:01 -0400435 texResource->resource(), &srcLocation, &srcBox);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400436 this->submitDirectCommandList(SyncQueue::kForce);
437
438 const void* mappedMemory = transferBuffer->map();
439
440 SkRectMemcpy(buffer, rowBytes, mappedMemory, dstLocation.PlacedFootprint.Footprint.RowPitch,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400441 tightRowBytes, height);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400442
443 transferBuffer->unmap();
444
445 return true;
446}
447
448bool GrD3DGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
449 GrColorType surfaceColorType, GrColorType srcColorType,
450 const GrMipLevel texels[], int mipLevelCount,
451 bool prepForTexSampling) {
452 GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
453 if (!d3dTex) {
454 return false;
455 }
456
457 // Make sure we have at least the base level
458 if (!mipLevelCount || !texels[0].fPixels) {
459 return false;
460 }
461
462 SkASSERT(!GrDxgiFormatIsCompressed(d3dTex->dxgiFormat()));
463 bool success = false;
464
465 // Need to change the resource state to COPY_DEST in order to upload to it
466 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
467
468 SkASSERT(mipLevelCount <= d3dTex->texturePriv().maxMipMapLevel() + 1);
469 success = this->uploadToTexture(d3dTex, left, top, width, height, srcColorType, texels,
470 mipLevelCount);
471
472 if (prepForTexSampling) {
473 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
474 }
475
476 return success;
477}
478
479bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex, int left, int top, int width, int height,
480 GrColorType colorType, const GrMipLevel* texels, int mipLevelCount) {
481 SkASSERT(this->caps()->isFormatTexturable(tex->backendFormat()));
482 // The assumption is either that we have no mipmaps, or that our rect is the entire texture
483 SkASSERT(1 == mipLevelCount ||
484 (0 == left && 0 == top && width == tex->width() && height == tex->height()));
485
486 // We assume that if the texture has mip levels, we either upload to all the levels or just the
487 // first.
488 SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
489
490 if (width == 0 || height == 0) {
491 return false;
492 }
493
494 SkASSERT(this->d3dCaps().surfaceSupportsWritePixels(tex));
495 SkASSERT(this->d3dCaps().areColorTypeAndFormatCompatible(colorType, tex->backendFormat()));
496
497 ID3D12Resource* d3dResource = tex->d3dResource();
498 SkASSERT(d3dResource);
499 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
500 // Either upload only the first miplevel or all miplevels
501 SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
502
503 if (1 == mipLevelCount && !texels[0].fPixels) {
504 return true; // no data to upload
505 }
506
507 for (int i = 0; i < mipLevelCount; ++i) {
508 // We do not allow any gaps in the mip data
509 if (!texels[i].fPixels) {
510 return false;
511 }
512 }
513
514 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400515 UINT64 combinedBufferSize;
516 // We reset the width and height in the description to match our subrectangle size
517 // so we don't end up allocating more space than we need.
518 desc.Width = width;
519 desc.Height = height;
520 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
Jim Van Verthfdd36852020-04-21 16:29:44 -0400521 nullptr, nullptr, &combinedBufferSize);
522 size_t bpp = GrColorTypeBytesPerPixel(colorType);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400523 SkASSERT(combinedBufferSize);
524
525 // TODO: do this until we have slices of buttery buffers
526 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(combinedBufferSize,
527 GrGpuBufferType::kXferCpuToGpu,
528 kDynamic_GrAccessPattern);
529 if (!transferBuffer) {
530 return false;
531 }
532 char* bufferData = (char*)transferBuffer->map();
533
534 int currentWidth = width;
535 int currentHeight = height;
536 int layerHeight = tex->height();
537
538 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
539 if (texels[currentMipLevel].fPixels) {
540 SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
541
Jim Van Verthfdd36852020-04-21 16:29:44 -0400542 const size_t trimRowBytes = currentWidth * bpp;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400543 const size_t srcRowBytes = texels[currentMipLevel].fRowBytes;
544
545 char* dst = bufferData + placedFootprints[currentMipLevel].Offset;
546
547 // copy data into the buffer, skipping any trailing bytes
Jim Van Verthba7f2292020-04-21 08:56:47 -0400548 const char* src = (const char*)texels[currentMipLevel].fPixels;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400549 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
550 src, srcRowBytes, trimRowBytes, currentHeight);
551 }
552 currentWidth = std::max(1, currentWidth / 2);
553 currentHeight = std::max(1, currentHeight / 2);
554 layerHeight = currentHeight;
555 }
556
557 transferBuffer->unmap();
558
559 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get());
560 fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, tex, mipLevelCount,
561 placedFootprints.get(), left, top);
562
563 if (mipLevelCount < (int)desc.MipLevels) {
564 tex->texturePriv().markMipMapsDirty();
565 }
566
567 return true;
568}
569
Michael Ludwig1e632792020-05-21 12:45:31 -0400570void GrD3DGpu::clear(const GrScissorState& scissor, const SkPMColor4f& color, GrRenderTarget* rt) {
Jim Van Verth280d4f72020-05-04 10:04:24 -0400571 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(rt);
572
573 d3dRT->setResourceState(this, D3D12_RESOURCE_STATE_RENDER_TARGET);
574
Michael Ludwig1e632792020-05-21 12:45:31 -0400575 fCurrentDirectCommandList->clearRenderTargetView(d3dRT, color, scissor);
Jim Van Verth280d4f72020-05-04 10:04:24 -0400576}
577
Jim Van Verth9145f782020-04-28 12:01:12 -0400578static bool check_resource_info(const GrD3DTextureResourceInfo& info) {
579 if (!info.fResource.get()) {
580 return false;
581 }
582 return true;
583}
584
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400585static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
586 if (!caps.isFormatTexturable(info.fFormat)) {
587 return false;
588 }
589 return true;
590}
591
592static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
593 int sampleCnt) {
594 if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
595 return false;
596 }
597 return true;
598}
599
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400600sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
601 GrWrapOwnership,
602 GrWrapCacheable wrapType,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400603 GrIOType ioType) {
604 GrD3DTextureResourceInfo textureInfo;
605 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
606 return nullptr;
607 }
608
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400609 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400610 return nullptr;
611 }
612
613 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
614 return nullptr;
615 }
616
617 // TODO: support protected context
618 if (tex.isProtected()) {
619 return nullptr;
620 }
621
622 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
623 SkASSERT(state);
624 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
625 std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500626}
627
628sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400629 GrWrapOwnership,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500630 GrWrapCacheable wrapType) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400631 GrD3DTextureResourceInfo textureInfo;
632 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
633 return nullptr;
634 }
635
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400636 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400637 return nullptr;
638 }
639
640 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
641 return nullptr;
642 }
643
644 // TODO: support protected context
645 if (tex.isProtected()) {
646 return nullptr;
647 }
648
649 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
650 SkASSERT(state);
651 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, kRead_GrIOType,
652 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500653}
654
655sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
656 int sampleCnt,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500657 GrWrapOwnership ownership,
658 GrWrapCacheable cacheable) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400659 GrD3DTextureResourceInfo textureInfo;
660 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
661 return nullptr;
662 }
663
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400664 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400665 return nullptr;
666 }
667
668 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
669 return nullptr;
670 }
671 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
672 return nullptr;
673 }
674
675 // TODO: support protected context
676 if (tex.isProtected()) {
677 return nullptr;
678 }
679
680 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
681
682 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
683 SkASSERT(state);
684
685 return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
686 sampleCnt, cacheable,
687 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500688}
689
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400690sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400691 // Currently the Direct3D backend does not support wrapping of msaa render targets directly. In
692 // general this is not an issue since swapchain images in D3D are never multisampled. Thus if
693 // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
694 // creating and owning the MSAA images.
695 if (rt.sampleCnt() > 1) {
696 return nullptr;
697 }
698
699 GrD3DTextureResourceInfo info;
700 if (!rt.getD3DTextureResourceInfo(&info)) {
701 return nullptr;
702 }
703
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400704 if (!check_resource_info(info)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400705 return nullptr;
706 }
707
708 if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
709 return nullptr;
710 }
711
712 // TODO: support protected context
713 if (rt.isProtected()) {
714 return nullptr;
715 }
716
717 sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
718
719 sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
720 this, rt.dimensions(), 1, info, std::move(state));
721
722 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
723 SkASSERT(!rt.stencilBits());
724 if (tgt) {
725 SkASSERT(tgt->canAttemptStencilAttachment());
726 }
727
728 return std::move(tgt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500729}
730
731sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400732 int sampleCnt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400733
734 GrD3DTextureResourceInfo textureInfo;
735 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
736 return nullptr;
737 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400738 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400739 return nullptr;
740 }
741
742 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
743 return nullptr;
744 }
745
746 // TODO: support protected context
747 if (tex.isProtected()) {
748 return nullptr;
749 }
750
751 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
752 if (!sampleCnt) {
753 return nullptr;
754 }
755
756 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
757 SkASSERT(state);
758
759 return GrD3DRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt,
760 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500761}
762
763sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
Jim Van Verthd6ad4802020-04-03 14:59:20 -0400764 GrAccessPattern accessPattern, const void* data) {
765 sk_sp<GrD3DBuffer> buffer = GrD3DBuffer::Make(this, sizeInBytes, type, accessPattern);
766 if (data && buffer) {
767 buffer->updateData(data, sizeInBytes);
768 }
769
770 return std::move(buffer);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500771}
772
773GrStencilAttachment* GrD3DGpu::createStencilAttachmentForRenderTarget(
774 const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
Jim Van Verth4f51f472020-04-13 11:02:21 -0400775 SkASSERT(numStencilSamples == rt->numSamples() || this->caps()->mixedSamplesSupport());
776 SkASSERT(width >= rt->width());
777 SkASSERT(height >= rt->height());
778
779 const GrD3DCaps::StencilFormat& sFmt = this->d3dCaps().preferredStencilFormat();
780
781 GrD3DStencilAttachment* stencil(GrD3DStencilAttachment::Make(this,
782 width,
783 height,
784 numStencilSamples,
785 sFmt));
786 fStats.incStencilAttachmentCreates();
787 return stencil;
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500788}
789
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400790bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
791 SkISize dimensions,
792 GrTexturable texturable,
793 GrRenderable renderable,
794 GrMipMapped mipMapped,
795 GrD3DTextureResourceInfo* info,
Greg Daniel16032b32020-05-06 15:31:10 -0400796 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400797 SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400798
799 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
800 return false;
801 }
802
803 if (texturable == GrTexturable::kYes && !this->d3dCaps().isFormatTexturable(dxgiFormat)) {
804 return false;
805 }
806
807 if (renderable == GrRenderable::kYes && !this->d3dCaps().isFormatRenderable(dxgiFormat, 1)) {
808 return false;
809 }
810
811 int numMipLevels = 1;
812 if (mipMapped == GrMipMapped::kYes) {
813 numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
814 }
815
816 // create the texture
817 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
818 if (renderable == GrRenderable::kYes) {
819 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
820 }
821
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400822 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400823 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
Greg Daniel16032b32020-05-06 15:31:10 -0400824 resourceDesc.Alignment = 0; // use default alignment
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400825 resourceDesc.Width = dimensions.fWidth;
826 resourceDesc.Height = dimensions.fHeight;
827 resourceDesc.DepthOrArraySize = 1;
828 resourceDesc.MipLevels = numMipLevels;
829 resourceDesc.Format = dxgiFormat;
830 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400831 // quality levels are only supported for tiled resources so ignore for now
832 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Greg Daniel16032b32020-05-06 15:31:10 -0400833 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400834 resourceDesc.Flags = usageFlags;
835
Jim Van Verth280d4f72020-05-04 10:04:24 -0400836 D3D12_CLEAR_VALUE* clearValuePtr = nullptr;
837 D3D12_CLEAR_VALUE clearValue = {};
838 if (renderable == GrRenderable::kYes) {
839 clearValue.Format = dxgiFormat;
840 // Assume transparent black
841 clearValue.Color[0] = 0;
842 clearValue.Color[1] = 0;
843 clearValue.Color[2] = 0;
844 clearValue.Color[3] = 0;
845 clearValuePtr = &clearValue;
846 }
847
Greg Daniel16032b32020-05-06 15:31:10 -0400848 D3D12_RESOURCE_STATES initialState = (renderable == GrRenderable::kYes)
849 ? D3D12_RESOURCE_STATE_RENDER_TARGET
850 : D3D12_RESOURCE_STATE_COPY_DEST;
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400851 if (!GrD3DTextureResource::InitTextureResourceInfo(this, resourceDesc, initialState,
Jim Van Verth280d4f72020-05-04 10:04:24 -0400852 isProtected, clearValuePtr, info)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400853 SkDebugf("Failed to init texture resource info\n");
854 return false;
855 }
856
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400857 return true;
858}
859
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500860GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400861 const GrBackendFormat& format,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400862 GrRenderable renderable,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400863 GrMipMapped mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400864 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400865 this->handleDirtyContext();
866
867 const GrD3DCaps& caps = this->d3dCaps();
868
869 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
870 return {};
871 }
872
873 DXGI_FORMAT dxgiFormat;
874 if (!format.asDxgiFormat(&dxgiFormat)) {
875 return {};
876 }
877
878 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
879 if (!caps.isFormatTexturable(dxgiFormat)) {
880 return {};
881 }
882
883 GrD3DTextureResourceInfo info;
884 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
885 renderable, mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400886 &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400887 return {};
888 }
889
890 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500891}
892
Greg Daniel16032b32020-05-06 15:31:10 -0400893bool GrD3DGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture,
894 sk_sp<GrRefCntedCallback> finishedCallback,
895 const BackendTextureData* data) {
896 // TODO: handle finishedCallback and data upload
897 return true;
898}
899
Greg Danielc1ad77c2020-05-06 11:40:03 -0400900GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(
901 SkISize dimensions, const GrBackendFormat& format, GrMipMapped mipMapped,
902 GrProtected isProtected, sk_sp<GrRefCntedCallback> finishedCallback,
903 const BackendTextureData* data) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400904 this->handleDirtyContext();
905
906 const GrD3DCaps& caps = this->d3dCaps();
907
908 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
909 return {};
910 }
911
912 DXGI_FORMAT dxgiFormat;
913 if (!format.asDxgiFormat(&dxgiFormat)) {
914 return {};
915 }
916
917 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
918 if (!caps.isFormatTexturable(dxgiFormat)) {
919 return {};
920 }
921
922 GrD3DTextureResourceInfo info;
923 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
924 GrRenderable::kNo, mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400925 &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400926 return {};
927 }
928
929 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500930}
931
932void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400933 SkASSERT(GrBackendApi::kDirect3D == tex.fBackend);
934 // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500935}
936
Robert Phillips979b2232020-02-20 10:47:29 -0500937bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
938 return false;
939}
940
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500941#if GR_TEST_UTILS
942bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400943 SkASSERT(GrBackendApi::kDirect3D == tex.backend());
944
945 GrD3DTextureResourceInfo info;
946 if (!tex.getD3DTextureResourceInfo(&info)) {
947 return false;
948 }
949 ID3D12Resource* textureResource = info.fResource.get();
950 if (!textureResource) {
951 return false;
952 }
953 return !(textureResource->GetDesc().Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500954}
955
956GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(int w, int h,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400957 GrColorType colorType) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400958 this->handleDirtyContext();
959
960 if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400961 return {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400962 }
963
964 DXGI_FORMAT dxgiFormat = this->d3dCaps().getFormatFromColorType(colorType);
965
966 GrD3DTextureResourceInfo info;
967 if (!this->createTextureResourceForBackendSurface(dxgiFormat, { w, h }, GrTexturable::kNo,
968 GrRenderable::kYes, GrMipMapped::kNo,
Greg Daniel16032b32020-05-06 15:31:10 -0400969 &info, GrProtected::kNo)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400970 return {};
971 }
972
973 return GrBackendRenderTarget(w, h, 1, info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500974}
975
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400976void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
977 SkASSERT(GrBackendApi::kDirect3D == rt.backend());
978
979 GrD3DTextureResourceInfo info;
980 if (rt.getD3DTextureResourceInfo(&info)) {
981 this->testingOnly_flushGpuAndSync();
982 // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
983 // is deleted.
984 }
985}
986
987void GrD3DGpu::testingOnly_flushGpuAndSync() {
Jim Van Verthc632aa62020-04-17 16:58:20 -0400988 SkAssertResult(this->submitDirectCommandList(SyncQueue::kForce));
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400989}
Jim Van Verthc632aa62020-04-17 16:58:20 -0400990
Jim Van Verth9b5e16c2020-04-20 10:45:52 -0400991void GrD3DGpu::testingOnly_startCapture() {
992 if (fGraphicsAnalysis) {
993 fGraphicsAnalysis->BeginCapture();
994 }
995}
996
997void GrD3DGpu::testingOnly_endCapture() {
998 if (fGraphicsAnalysis) {
999 fGraphicsAnalysis->EndCapture();
1000 }
1001}
1002#endif
1003
Jim Van Verthc632aa62020-04-17 16:58:20 -04001004///////////////////////////////////////////////////////////////////////////////
1005
Greg Daniela5a6b322020-04-23 12:52:27 -04001006void GrD3DGpu::addResourceBarriers(sk_sp<GrManagedResource> resource,
Jim Van Verthc632aa62020-04-17 16:58:20 -04001007 int numBarriers,
1008 D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
1009 SkASSERT(fCurrentDirectCommandList);
1010 SkASSERT(resource);
1011
Greg Daniela5a6b322020-04-23 12:52:27 -04001012 fCurrentDirectCommandList->resourceBarrier(std::move(resource), numBarriers, barriers);
Jim Van Verthc632aa62020-04-17 16:58:20 -04001013}
1014
Jim Van Verth682a2f42020-05-13 16:54:09 -04001015void GrD3DGpu::prepareSurfacesForBackendAccessAndExternalIO(
1016 GrSurfaceProxy* proxies[], int numProxies, SkSurface::BackendSurfaceAccess access,
1017 const GrPrepareForExternalIORequests& externalRequests) {
1018 SkASSERT(numProxies >= 0);
1019 SkASSERT(!numProxies || proxies);
1020
1021 // prepare proxies by transitioning to PRESENT renderState
1022 if (numProxies && access == SkSurface::BackendSurfaceAccess::kPresent) {
1023 GrD3DTextureResource* resource;
1024 for (int i = 0; i < numProxies; ++i) {
1025 SkASSERT(proxies[i]->isInstantiated());
1026 if (GrTexture* tex = proxies[i]->peekTexture()) {
1027 resource = static_cast<GrD3DTexture*>(tex);
1028 } else {
1029 GrRenderTarget* rt = proxies[i]->peekRenderTarget();
1030 SkASSERT(rt);
1031 resource = static_cast<GrD3DRenderTarget*>(rt);
1032 }
1033 resource->prepareForPresent(this);
1034 }
1035 }
1036}
1037
Jim Van Verthc632aa62020-04-17 16:58:20 -04001038bool GrD3DGpu::onSubmitToGpu(bool syncCpu) {
1039 if (syncCpu) {
1040 return this->submitDirectCommandList(SyncQueue::kForce);
1041 } else {
1042 return this->submitDirectCommandList(SyncQueue::kSkip);
1043 }
1044}