blob: 7a50f01008ff20926c81c2c0d5772660bbd5e0f1 [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(
Robert Phillips96f22372020-05-20 12:31:18 -040096 GrRenderTarget* rt, GrStencilAttachment*,
97 GrSurfaceOrigin origin, const SkIRect& bounds,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050098 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
Greg Daniel31a7b072020-02-26 15:31:49 -050099 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500100 const SkTArray<GrSurfaceProxy*, true>& sampledProxies) {
Greg Daniel31a7b072020-02-26 15:31:49 -0500101 if (!fCachedOpsRenderPass) {
102 fCachedOpsRenderPass.reset(new GrD3DOpsRenderPass(this));
103 }
104
105 if (!fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies)) {
106 return nullptr;
107 }
108 return fCachedOpsRenderPass.get();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500109}
110
Jim Van Verthc632aa62020-04-17 16:58:20 -0400111bool GrD3DGpu::submitDirectCommandList(SyncQueue sync) {
Greg Daniel83ed2132020-03-24 13:15:33 -0400112 SkASSERT(fCurrentDirectCommandList);
113
Jim Van Verth3eadce22020-06-01 11:34:49 -0400114 fResourceProvider.prepForSubmit();
115
Jim Van Verthc632aa62020-04-17 16:58:20 -0400116 GrD3DDirectCommandList::SubmitResult result = fCurrentDirectCommandList->submit(fQueue.get());
117 if (result == GrD3DDirectCommandList::SubmitResult::kFailure) {
118 return false;
119 } else if (result == GrD3DDirectCommandList::SubmitResult::kNoWork) {
120 if (sync == SyncQueue::kForce) {
121 this->waitForQueueCompletion();
Jim Van Verth682a2f42020-05-13 16:54:09 -0400122 this->checkForFinishedCommandLists();
Jim Van Verthc632aa62020-04-17 16:58:20 -0400123 }
124 return true;
125 }
Greg Daniel83ed2132020-03-24 13:15:33 -0400126
127 new (fOutstandingCommandLists.push_back()) OutstandingCommandList(
128 std::move(fCurrentDirectCommandList), ++fCurrentFenceValue);
129
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400130 SkDEBUGCODE(HRESULT hr = ) fQueue->Signal(fFence.get(), fCurrentFenceValue);
Greg Daniel83ed2132020-03-24 13:15:33 -0400131 SkASSERT(SUCCEEDED(hr));
132
Jim Van Verthc632aa62020-04-17 16:58:20 -0400133 if (sync == SyncQueue::kForce) {
134 this->waitForQueueCompletion();
135 }
136
Greg Daniel83ed2132020-03-24 13:15:33 -0400137 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
138
139 // This should be done after we have a new command list in case the freeing of any resources
140 // held by a finished command list causes us send a new command to the gpu (like changing the
141 // resource state.
142 this->checkForFinishedCommandLists();
143
144 SkASSERT(fCurrentDirectCommandList);
Jim Van Verthc632aa62020-04-17 16:58:20 -0400145 return true;
Greg Daniel83ed2132020-03-24 13:15:33 -0400146}
147
148void GrD3DGpu::checkForFinishedCommandLists() {
149 uint64_t currentFenceValue = fFence->GetCompletedValue();
150
151 // Iterate over all the outstanding command lists to see if any have finished. The commands
152 // lists are in order from oldest to newest, so we start at the front to check if their fence
153 // value is less than the last signaled value. If so we pop it off and move onto the next.
154 // Repeat till we find a command list that has not finished yet (and all others afterwards are
155 // also guaranteed to not have finished).
156 SkDeque::F2BIter iter(fOutstandingCommandLists);
157 const OutstandingCommandList* curList = (const OutstandingCommandList*)iter.next();
158 while (curList && curList->fFenceValue <= currentFenceValue) {
159 curList = (const OutstandingCommandList*)iter.next();
160 OutstandingCommandList* front = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel7a5f1fa2020-03-24 14:50:19 -0400161 fResourceProvider.recycleDirectCommandList(std::move(front->fCommandList));
Greg Daniel83ed2132020-03-24 13:15:33 -0400162 // Since we used placement new we are responsible for calling the destructor manually.
163 front->~OutstandingCommandList();
164 fOutstandingCommandLists.pop_front();
165 }
166}
167
Jim Van Verthc632aa62020-04-17 16:58:20 -0400168void GrD3DGpu::waitForQueueCompletion() {
169 if (fFence->GetCompletedValue() < fCurrentFenceValue) {
170 HANDLE fenceEvent;
171 fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
172 SkASSERT(fenceEvent);
173 SkDEBUGCODE(HRESULT hr = ) fFence->SetEventOnCompletion(fCurrentFenceValue, fenceEvent);
174 SkASSERT(SUCCEEDED(hr));
175 WaitForSingleObject(fenceEvent, INFINITE);
176 CloseHandle(fenceEvent);
177 }
178}
179
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500180void GrD3DGpu::submit(GrOpsRenderPass* renderPass) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400181 SkASSERT(fCachedOpsRenderPass.get() == renderPass);
182
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500183 // TODO: actually submit something here
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400184 fCachedOpsRenderPass.reset();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500185}
186
187void GrD3DGpu::querySampleLocations(GrRenderTarget* rt, SkTArray<SkPoint>* sampleLocations) {
188 // TODO
189}
190
191sk_sp<GrTexture> GrD3DGpu::onCreateTexture(SkISize dimensions,
192 const GrBackendFormat& format,
193 GrRenderable renderable,
194 int renderTargetSampleCnt,
195 SkBudgeted budgeted,
196 GrProtected isProtected,
197 int mipLevelCount,
198 uint32_t levelClearMask) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400199 DXGI_FORMAT dxgiFormat;
200 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
201 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
202
203 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
204
205 if (renderable == GrRenderable::kYes) {
206 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
207 }
208
209 // This desc refers to the texture that will be read by the client. Thus even if msaa is
210 // requested, this describes the resolved texture. Therefore we always have samples set
211 // to 1.
212 SkASSERT(mipLevelCount > 0);
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400213 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400214 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
215 // TODO: will use 4MB alignment for MSAA textures and 64KB for everything else
216 // might want to manually set alignment to 4KB for smaller textures
217 resourceDesc.Alignment = 0;
218 resourceDesc.Width = dimensions.fWidth;
219 resourceDesc.Height = dimensions.fHeight;
220 resourceDesc.DepthOrArraySize = 1;
221 resourceDesc.MipLevels = mipLevelCount;
222 resourceDesc.Format = dxgiFormat;
223 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400224 // quality levels are only supported for tiled resources so ignore for now
225 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400226 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400227 resourceDesc.Flags = usageFlags;
228
229 GrMipMapsStatus mipMapsStatus =
230 mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
231
232 sk_sp<GrD3DTexture> tex;
233 if (renderable == GrRenderable::kYes) {
234 tex = GrD3DTextureRenderTarget::MakeNewTextureRenderTarget(
235 this, budgeted, dimensions, renderTargetSampleCnt, resourceDesc, isProtected,
236 mipMapsStatus);
237 } else {
238 tex = GrD3DTexture::MakeNewTexture(this, budgeted, dimensions, resourceDesc, isProtected,
239 mipMapsStatus);
240 }
241
242 if (!tex) {
243 return nullptr;
244 }
245
246 if (levelClearMask) {
247 // TODO
248 }
249 return std::move(tex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500250}
251
252sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
253 const GrBackendFormat& format,
254 SkBudgeted budgeted,
255 GrMipMapped mipMapped,
256 GrProtected isProtected,
257 const void* data, size_t dataSize) {
258 // TODO
259 return nullptr;
260}
261
Jim Van Verth9145f782020-04-28 12:01:12 -0400262static int get_surface_sample_cnt(GrSurface* surf) {
263 if (const GrRenderTarget* rt = surf->asRenderTarget()) {
264 return rt->numSamples();
265 }
266 return 0;
267}
268
269bool GrD3DGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
270 const SkIPoint& dstPoint) {
271
272 if (src->isProtected() && !dst->isProtected()) {
273 SkDebugf("Can't copy from protected memory to non-protected");
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400274 return false;
275 }
Jim Van Verth9145f782020-04-28 12:01:12 -0400276
277 int dstSampleCnt = get_surface_sample_cnt(dst);
278 int srcSampleCnt = get_surface_sample_cnt(src);
279
280 GrD3DTextureResource* dstTexResource;
281 GrD3DTextureResource* srcTexResource;
282 GrRenderTarget* dstRT = dst->asRenderTarget();
283 if (dstRT) {
284 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(dstRT);
285 dstTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
286 } else {
287 SkASSERT(dst->asTexture());
288 dstTexResource = static_cast<GrD3DTexture*>(dst->asTexture());
289 }
290 GrRenderTarget* srcRT = src->asRenderTarget();
291 if (srcRT) {
292 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(srcRT);
293 srcTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
294 } else {
295 SkASSERT(src->asTexture());
296 srcTexResource = static_cast<GrD3DTexture*>(src->asTexture());
297 }
298
299 DXGI_FORMAT dstFormat = dstTexResource->dxgiFormat();
300 DXGI_FORMAT srcFormat = srcTexResource->dxgiFormat();
301
302 if (this->d3dCaps().canCopyAsResolve(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
303 this->copySurfaceAsResolve(dst, src, srcRect, dstPoint);
304 return true;
305 }
306
307 if (this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
308 this->copySurfaceAsCopyTexture(dst, src, dstTexResource, srcTexResource, srcRect, dstPoint);
309 return true;
310 }
311
312 return false;
313}
314
315void GrD3DGpu::copySurfaceAsCopyTexture(GrSurface* dst, GrSurface* src,
316 GrD3DTextureResource* dstResource,
317 GrD3DTextureResource* srcResource,
318 const SkIRect& srcRect, const SkIPoint& dstPoint) {
319#ifdef SK_DEBUG
320 int dstSampleCnt = get_surface_sample_cnt(dst);
321 int srcSampleCnt = get_surface_sample_cnt(src);
322 DXGI_FORMAT dstFormat = dstResource->dxgiFormat();
323 DXGI_FORMAT srcFormat;
324 SkAssertResult(dst->backendFormat().asDxgiFormat(&srcFormat));
325 SkASSERT(this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt));
326#endif
327 if (src->isProtected() && !dst->isProtected()) {
328 SkDebugf("Can't copy from protected memory to non-protected");
329 return;
330 }
331
332 dstResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
333 srcResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
334
335 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
336 dstLocation.pResource = dstResource->d3dResource();
337 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
338 dstLocation.SubresourceIndex = 0;
339
340 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
341 srcLocation.pResource = srcResource->d3dResource();
342 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
343 srcLocation.SubresourceIndex = 0;
344
345 D3D12_BOX srcBox = {};
346 srcBox.left = srcRect.fLeft;
347 srcBox.top = srcRect.fTop;
348 srcBox.right = srcRect.fRight;
349 srcBox.bottom = srcRect.fBottom;
350 srcBox.front = 0;
351 srcBox.back = 1;
352 // TODO: use copyResource if copying full resource and sizes match
353 fCurrentDirectCommandList->copyTextureRegion(dstResource->resource(),
354 &dstLocation,
355 dstPoint.fX, dstPoint.fY,
356 srcResource->resource(),
357 &srcLocation,
358 &srcBox);
359
360 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
361 srcRect.width(), srcRect.height());
362 // The rect is already in device space so we pass in kTopLeft so no flip is done.
363 this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
364}
365
366void GrD3DGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
367 const SkIPoint& dstPoint) {
368 // TODO
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400369}
370
Jim Van Verthba7f2292020-04-21 08:56:47 -0400371bool GrD3DGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
372 GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
373 size_t rowBytes) {
374 SkASSERT(surface);
375
376 if (surfaceColorType != dstColorType) {
377 return false;
378 }
379
380 // Set up src location and box
Jim Van Verthc12aad92020-04-24 16:19:01 -0400381 GrD3DTextureResource* texResource = nullptr;
382 GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(surface->asRenderTarget());
383 if (rt) {
384 texResource = rt;
385 } else {
386 texResource = static_cast<GrD3DTexture*>(surface->asTexture());
387 }
388
389 if (!texResource) {
Jim Van Verthba7f2292020-04-21 08:56:47 -0400390 return false;
391 }
Jim Van Verthc12aad92020-04-24 16:19:01 -0400392
Jim Van Verthba7f2292020-04-21 08:56:47 -0400393 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
Jim Van Verthc12aad92020-04-24 16:19:01 -0400394 srcLocation.pResource = texResource->d3dResource();
Jim Van Verthba7f2292020-04-21 08:56:47 -0400395 SkASSERT(srcLocation.pResource);
396 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
397 srcLocation.SubresourceIndex = 0;
398
399 D3D12_BOX srcBox = {};
400 srcBox.left = left;
401 srcBox.top = top;
402 srcBox.right = left + width;
403 srcBox.bottom = top + height;
404 srcBox.front = 0;
405 srcBox.back = 1;
406
407 // Set up dst location and create transfer buffer
408 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
409 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400410 UINT64 transferTotalBytes;
411 const UINT64 baseOffset = 0;
412 D3D12_RESOURCE_DESC desc = srcLocation.pResource->GetDesc();
413 fDevice->GetCopyableFootprints(&desc, 0, 1, baseOffset, &dstLocation.PlacedFootprint,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400414 nullptr, nullptr, &transferTotalBytes);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400415 SkASSERT(transferTotalBytes);
Jim Van Verthfdd36852020-04-21 16:29:44 -0400416 size_t bpp = GrColorTypeBytesPerPixel(dstColorType);
Jim Van Verthc12aad92020-04-24 16:19:01 -0400417 if (this->d3dCaps().bytesPerPixel(texResource->dxgiFormat()) != bpp) {
Jim Van Verthfdd36852020-04-21 16:29:44 -0400418 return false;
419 }
420 size_t tightRowBytes = bpp * width;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400421
422 // TODO: implement some way of reusing buffers instead of making a new one every time.
423 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(transferTotalBytes,
424 GrGpuBufferType::kXferGpuToCpu,
425 kDynamic_GrAccessPattern);
426 GrD3DBuffer* d3dBuf = static_cast<GrD3DBuffer*>(transferBuffer.get());
427 dstLocation.pResource = d3dBuf->d3dResource();
428
429 // Need to change the resource state to COPY_SOURCE in order to download from it
Jim Van Verthc12aad92020-04-24 16:19:01 -0400430 texResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400431
432 fCurrentDirectCommandList->copyTextureRegion(d3dBuf->resource(), &dstLocation, 0, 0,
Jim Van Verthc12aad92020-04-24 16:19:01 -0400433 texResource->resource(), &srcLocation, &srcBox);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400434 this->submitDirectCommandList(SyncQueue::kForce);
435
436 const void* mappedMemory = transferBuffer->map();
437
438 SkRectMemcpy(buffer, rowBytes, mappedMemory, dstLocation.PlacedFootprint.Footprint.RowPitch,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400439 tightRowBytes, height);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400440
441 transferBuffer->unmap();
442
443 return true;
444}
445
446bool GrD3DGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
447 GrColorType surfaceColorType, GrColorType srcColorType,
448 const GrMipLevel texels[], int mipLevelCount,
449 bool prepForTexSampling) {
450 GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
451 if (!d3dTex) {
452 return false;
453 }
454
455 // Make sure we have at least the base level
456 if (!mipLevelCount || !texels[0].fPixels) {
457 return false;
458 }
459
460 SkASSERT(!GrDxgiFormatIsCompressed(d3dTex->dxgiFormat()));
461 bool success = false;
462
463 // Need to change the resource state to COPY_DEST in order to upload to it
464 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
465
466 SkASSERT(mipLevelCount <= d3dTex->texturePriv().maxMipMapLevel() + 1);
467 success = this->uploadToTexture(d3dTex, left, top, width, height, srcColorType, texels,
468 mipLevelCount);
469
470 if (prepForTexSampling) {
471 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
472 }
473
474 return success;
475}
476
477bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex, int left, int top, int width, int height,
478 GrColorType colorType, const GrMipLevel* texels, int mipLevelCount) {
479 SkASSERT(this->caps()->isFormatTexturable(tex->backendFormat()));
480 // The assumption is either that we have no mipmaps, or that our rect is the entire texture
481 SkASSERT(1 == mipLevelCount ||
482 (0 == left && 0 == top && width == tex->width() && height == tex->height()));
483
484 // We assume that if the texture has mip levels, we either upload to all the levels or just the
485 // first.
486 SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
487
488 if (width == 0 || height == 0) {
489 return false;
490 }
491
492 SkASSERT(this->d3dCaps().surfaceSupportsWritePixels(tex));
493 SkASSERT(this->d3dCaps().areColorTypeAndFormatCompatible(colorType, tex->backendFormat()));
494
495 ID3D12Resource* d3dResource = tex->d3dResource();
496 SkASSERT(d3dResource);
497 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
498 // Either upload only the first miplevel or all miplevels
499 SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
500
501 if (1 == mipLevelCount && !texels[0].fPixels) {
502 return true; // no data to upload
503 }
504
505 for (int i = 0; i < mipLevelCount; ++i) {
506 // We do not allow any gaps in the mip data
507 if (!texels[i].fPixels) {
508 return false;
509 }
510 }
511
512 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400513 UINT64 combinedBufferSize;
514 // We reset the width and height in the description to match our subrectangle size
515 // so we don't end up allocating more space than we need.
516 desc.Width = width;
517 desc.Height = height;
518 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
Jim Van Verthfdd36852020-04-21 16:29:44 -0400519 nullptr, nullptr, &combinedBufferSize);
520 size_t bpp = GrColorTypeBytesPerPixel(colorType);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400521 SkASSERT(combinedBufferSize);
522
523 // TODO: do this until we have slices of buttery buffers
524 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(combinedBufferSize,
525 GrGpuBufferType::kXferCpuToGpu,
526 kDynamic_GrAccessPattern);
527 if (!transferBuffer) {
528 return false;
529 }
530 char* bufferData = (char*)transferBuffer->map();
531
532 int currentWidth = width;
533 int currentHeight = height;
534 int layerHeight = tex->height();
535
536 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
537 if (texels[currentMipLevel].fPixels) {
538 SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
539
Jim Van Verthfdd36852020-04-21 16:29:44 -0400540 const size_t trimRowBytes = currentWidth * bpp;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400541 const size_t srcRowBytes = texels[currentMipLevel].fRowBytes;
542
543 char* dst = bufferData + placedFootprints[currentMipLevel].Offset;
544
545 // copy data into the buffer, skipping any trailing bytes
Jim Van Verthba7f2292020-04-21 08:56:47 -0400546 const char* src = (const char*)texels[currentMipLevel].fPixels;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400547 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
548 src, srcRowBytes, trimRowBytes, currentHeight);
549 }
550 currentWidth = std::max(1, currentWidth / 2);
551 currentHeight = std::max(1, currentHeight / 2);
552 layerHeight = currentHeight;
553 }
554
555 transferBuffer->unmap();
556
557 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get());
558 fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, tex, mipLevelCount,
559 placedFootprints.get(), left, top);
560
561 if (mipLevelCount < (int)desc.MipLevels) {
562 tex->texturePriv().markMipMapsDirty();
563 }
564
565 return true;
566}
567
Michael Ludwig1e632792020-05-21 12:45:31 -0400568void GrD3DGpu::clear(const GrScissorState& scissor, const SkPMColor4f& color, GrRenderTarget* rt) {
Jim Van Verth280d4f72020-05-04 10:04:24 -0400569 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(rt);
570
571 d3dRT->setResourceState(this, D3D12_RESOURCE_STATE_RENDER_TARGET);
572
Michael Ludwig1e632792020-05-21 12:45:31 -0400573 fCurrentDirectCommandList->clearRenderTargetView(d3dRT, color, scissor);
Jim Van Verth280d4f72020-05-04 10:04:24 -0400574}
575
Jim Van Verth9145f782020-04-28 12:01:12 -0400576static bool check_resource_info(const GrD3DTextureResourceInfo& info) {
577 if (!info.fResource.get()) {
578 return false;
579 }
580 return true;
581}
582
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400583static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
584 if (!caps.isFormatTexturable(info.fFormat)) {
585 return false;
586 }
587 return true;
588}
589
590static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
591 int sampleCnt) {
592 if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
593 return false;
594 }
595 return true;
596}
597
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400598sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
599 GrWrapOwnership,
600 GrWrapCacheable wrapType,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400601 GrIOType ioType) {
602 GrD3DTextureResourceInfo textureInfo;
603 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
604 return nullptr;
605 }
606
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400607 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400608 return nullptr;
609 }
610
611 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
612 return nullptr;
613 }
614
615 // TODO: support protected context
616 if (tex.isProtected()) {
617 return nullptr;
618 }
619
620 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
621 SkASSERT(state);
622 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
623 std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500624}
625
626sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400627 GrWrapOwnership,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500628 GrWrapCacheable wrapType) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400629 GrD3DTextureResourceInfo textureInfo;
630 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
631 return nullptr;
632 }
633
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400634 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400635 return nullptr;
636 }
637
638 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
639 return nullptr;
640 }
641
642 // TODO: support protected context
643 if (tex.isProtected()) {
644 return nullptr;
645 }
646
647 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
648 SkASSERT(state);
649 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, kRead_GrIOType,
650 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500651}
652
653sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
654 int sampleCnt,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500655 GrWrapOwnership ownership,
656 GrWrapCacheable cacheable) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400657 GrD3DTextureResourceInfo textureInfo;
658 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
659 return nullptr;
660 }
661
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400662 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400663 return nullptr;
664 }
665
666 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
667 return nullptr;
668 }
669 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
670 return nullptr;
671 }
672
673 // TODO: support protected context
674 if (tex.isProtected()) {
675 return nullptr;
676 }
677
678 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
679
680 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
681 SkASSERT(state);
682
683 return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
684 sampleCnt, cacheable,
685 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500686}
687
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400688sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400689 // Currently the Direct3D backend does not support wrapping of msaa render targets directly. In
690 // general this is not an issue since swapchain images in D3D are never multisampled. Thus if
691 // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
692 // creating and owning the MSAA images.
693 if (rt.sampleCnt() > 1) {
694 return nullptr;
695 }
696
697 GrD3DTextureResourceInfo info;
698 if (!rt.getD3DTextureResourceInfo(&info)) {
699 return nullptr;
700 }
701
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400702 if (!check_resource_info(info)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400703 return nullptr;
704 }
705
706 if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
707 return nullptr;
708 }
709
710 // TODO: support protected context
711 if (rt.isProtected()) {
712 return nullptr;
713 }
714
715 sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
716
717 sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
718 this, rt.dimensions(), 1, info, std::move(state));
719
720 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
721 SkASSERT(!rt.stencilBits());
722 if (tgt) {
723 SkASSERT(tgt->canAttemptStencilAttachment());
724 }
725
726 return std::move(tgt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500727}
728
729sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400730 int sampleCnt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400731
732 GrD3DTextureResourceInfo textureInfo;
733 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
734 return nullptr;
735 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400736 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400737 return nullptr;
738 }
739
740 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
741 return nullptr;
742 }
743
744 // TODO: support protected context
745 if (tex.isProtected()) {
746 return nullptr;
747 }
748
749 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
750 if (!sampleCnt) {
751 return nullptr;
752 }
753
754 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
755 SkASSERT(state);
756
757 return GrD3DRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt,
758 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500759}
760
761sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
Jim Van Verthd6ad4802020-04-03 14:59:20 -0400762 GrAccessPattern accessPattern, const void* data) {
763 sk_sp<GrD3DBuffer> buffer = GrD3DBuffer::Make(this, sizeInBytes, type, accessPattern);
764 if (data && buffer) {
765 buffer->updateData(data, sizeInBytes);
766 }
767
768 return std::move(buffer);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500769}
770
771GrStencilAttachment* GrD3DGpu::createStencilAttachmentForRenderTarget(
772 const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
Jim Van Verth4f51f472020-04-13 11:02:21 -0400773 SkASSERT(numStencilSamples == rt->numSamples() || this->caps()->mixedSamplesSupport());
774 SkASSERT(width >= rt->width());
775 SkASSERT(height >= rt->height());
776
777 const GrD3DCaps::StencilFormat& sFmt = this->d3dCaps().preferredStencilFormat();
778
779 GrD3DStencilAttachment* stencil(GrD3DStencilAttachment::Make(this,
780 width,
781 height,
782 numStencilSamples,
783 sFmt));
784 fStats.incStencilAttachmentCreates();
785 return stencil;
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500786}
787
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400788bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
789 SkISize dimensions,
790 GrTexturable texturable,
791 GrRenderable renderable,
792 GrMipMapped mipMapped,
793 GrD3DTextureResourceInfo* info,
Greg Daniel16032b32020-05-06 15:31:10 -0400794 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400795 SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400796
797 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
798 return false;
799 }
800
801 if (texturable == GrTexturable::kYes && !this->d3dCaps().isFormatTexturable(dxgiFormat)) {
802 return false;
803 }
804
805 if (renderable == GrRenderable::kYes && !this->d3dCaps().isFormatRenderable(dxgiFormat, 1)) {
806 return false;
807 }
808
809 int numMipLevels = 1;
810 if (mipMapped == GrMipMapped::kYes) {
811 numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
812 }
813
814 // create the texture
815 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
816 if (renderable == GrRenderable::kYes) {
817 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
818 }
819
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400820 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400821 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
Greg Daniel16032b32020-05-06 15:31:10 -0400822 resourceDesc.Alignment = 0; // use default alignment
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400823 resourceDesc.Width = dimensions.fWidth;
824 resourceDesc.Height = dimensions.fHeight;
825 resourceDesc.DepthOrArraySize = 1;
826 resourceDesc.MipLevels = numMipLevels;
827 resourceDesc.Format = dxgiFormat;
828 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400829 // quality levels are only supported for tiled resources so ignore for now
830 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Greg Daniel16032b32020-05-06 15:31:10 -0400831 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400832 resourceDesc.Flags = usageFlags;
833
Jim Van Verth280d4f72020-05-04 10:04:24 -0400834 D3D12_CLEAR_VALUE* clearValuePtr = nullptr;
835 D3D12_CLEAR_VALUE clearValue = {};
836 if (renderable == GrRenderable::kYes) {
837 clearValue.Format = dxgiFormat;
838 // Assume transparent black
839 clearValue.Color[0] = 0;
840 clearValue.Color[1] = 0;
841 clearValue.Color[2] = 0;
842 clearValue.Color[3] = 0;
843 clearValuePtr = &clearValue;
844 }
845
Greg Daniel16032b32020-05-06 15:31:10 -0400846 D3D12_RESOURCE_STATES initialState = (renderable == GrRenderable::kYes)
847 ? D3D12_RESOURCE_STATE_RENDER_TARGET
848 : D3D12_RESOURCE_STATE_COPY_DEST;
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400849 if (!GrD3DTextureResource::InitTextureResourceInfo(this, resourceDesc, initialState,
Jim Van Verth280d4f72020-05-04 10:04:24 -0400850 isProtected, clearValuePtr, info)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400851 SkDebugf("Failed to init texture resource info\n");
852 return false;
853 }
854
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400855 return true;
856}
857
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500858GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400859 const GrBackendFormat& format,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400860 GrRenderable renderable,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400861 GrMipMapped mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400862 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400863 this->handleDirtyContext();
864
865 const GrD3DCaps& caps = this->d3dCaps();
866
867 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
868 return {};
869 }
870
871 DXGI_FORMAT dxgiFormat;
872 if (!format.asDxgiFormat(&dxgiFormat)) {
873 return {};
874 }
875
876 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
877 if (!caps.isFormatTexturable(dxgiFormat)) {
878 return {};
879 }
880
881 GrD3DTextureResourceInfo info;
882 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
883 renderable, mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400884 &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400885 return {};
886 }
887
888 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500889}
890
Greg Daniel16032b32020-05-06 15:31:10 -0400891bool GrD3DGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture,
892 sk_sp<GrRefCntedCallback> finishedCallback,
893 const BackendTextureData* data) {
894 // TODO: handle finishedCallback and data upload
895 return true;
896}
897
Greg Danielc1ad77c2020-05-06 11:40:03 -0400898GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(
899 SkISize dimensions, const GrBackendFormat& format, GrMipMapped mipMapped,
900 GrProtected isProtected, sk_sp<GrRefCntedCallback> finishedCallback,
901 const BackendTextureData* data) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400902 this->handleDirtyContext();
903
904 const GrD3DCaps& caps = this->d3dCaps();
905
906 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
907 return {};
908 }
909
910 DXGI_FORMAT dxgiFormat;
911 if (!format.asDxgiFormat(&dxgiFormat)) {
912 return {};
913 }
914
915 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
916 if (!caps.isFormatTexturable(dxgiFormat)) {
917 return {};
918 }
919
920 GrD3DTextureResourceInfo info;
921 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
922 GrRenderable::kNo, mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400923 &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400924 return {};
925 }
926
927 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500928}
929
930void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400931 SkASSERT(GrBackendApi::kDirect3D == tex.fBackend);
932 // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500933}
934
Robert Phillips979b2232020-02-20 10:47:29 -0500935bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
936 return false;
937}
938
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500939#if GR_TEST_UTILS
940bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400941 SkASSERT(GrBackendApi::kDirect3D == tex.backend());
942
943 GrD3DTextureResourceInfo info;
944 if (!tex.getD3DTextureResourceInfo(&info)) {
945 return false;
946 }
947 ID3D12Resource* textureResource = info.fResource.get();
948 if (!textureResource) {
949 return false;
950 }
951 return !(textureResource->GetDesc().Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500952}
953
954GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(int w, int h,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400955 GrColorType colorType) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400956 this->handleDirtyContext();
957
958 if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400959 return {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400960 }
961
962 DXGI_FORMAT dxgiFormat = this->d3dCaps().getFormatFromColorType(colorType);
963
964 GrD3DTextureResourceInfo info;
965 if (!this->createTextureResourceForBackendSurface(dxgiFormat, { w, h }, GrTexturable::kNo,
966 GrRenderable::kYes, GrMipMapped::kNo,
Greg Daniel16032b32020-05-06 15:31:10 -0400967 &info, GrProtected::kNo)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400968 return {};
969 }
970
971 return GrBackendRenderTarget(w, h, 1, info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500972}
973
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400974void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
975 SkASSERT(GrBackendApi::kDirect3D == rt.backend());
976
977 GrD3DTextureResourceInfo info;
978 if (rt.getD3DTextureResourceInfo(&info)) {
979 this->testingOnly_flushGpuAndSync();
980 // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
981 // is deleted.
982 }
983}
984
985void GrD3DGpu::testingOnly_flushGpuAndSync() {
Jim Van Verthc632aa62020-04-17 16:58:20 -0400986 SkAssertResult(this->submitDirectCommandList(SyncQueue::kForce));
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400987}
Jim Van Verthc632aa62020-04-17 16:58:20 -0400988
Jim Van Verth9b5e16c2020-04-20 10:45:52 -0400989void GrD3DGpu::testingOnly_startCapture() {
990 if (fGraphicsAnalysis) {
991 fGraphicsAnalysis->BeginCapture();
992 }
993}
994
995void GrD3DGpu::testingOnly_endCapture() {
996 if (fGraphicsAnalysis) {
997 fGraphicsAnalysis->EndCapture();
998 }
999}
1000#endif
1001
Jim Van Verthc632aa62020-04-17 16:58:20 -04001002///////////////////////////////////////////////////////////////////////////////
1003
Greg Daniela5a6b322020-04-23 12:52:27 -04001004void GrD3DGpu::addResourceBarriers(sk_sp<GrManagedResource> resource,
Jim Van Verthc632aa62020-04-17 16:58:20 -04001005 int numBarriers,
1006 D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
1007 SkASSERT(fCurrentDirectCommandList);
1008 SkASSERT(resource);
1009
Greg Daniela5a6b322020-04-23 12:52:27 -04001010 fCurrentDirectCommandList->resourceBarrier(std::move(resource), numBarriers, barriers);
Jim Van Verthc632aa62020-04-17 16:58:20 -04001011}
1012
Jim Van Verth682a2f42020-05-13 16:54:09 -04001013void GrD3DGpu::prepareSurfacesForBackendAccessAndExternalIO(
1014 GrSurfaceProxy* proxies[], int numProxies, SkSurface::BackendSurfaceAccess access,
1015 const GrPrepareForExternalIORequests& externalRequests) {
1016 SkASSERT(numProxies >= 0);
1017 SkASSERT(!numProxies || proxies);
1018
1019 // prepare proxies by transitioning to PRESENT renderState
1020 if (numProxies && access == SkSurface::BackendSurfaceAccess::kPresent) {
1021 GrD3DTextureResource* resource;
1022 for (int i = 0; i < numProxies; ++i) {
1023 SkASSERT(proxies[i]->isInstantiated());
1024 if (GrTexture* tex = proxies[i]->peekTexture()) {
1025 resource = static_cast<GrD3DTexture*>(tex);
1026 } else {
1027 GrRenderTarget* rt = proxies[i]->peekRenderTarget();
1028 SkASSERT(rt);
1029 resource = static_cast<GrD3DRenderTarget*>(rt);
1030 }
1031 resource->prepareForPresent(this);
1032 }
1033 }
1034}
1035
Jim Van Verthc632aa62020-04-17 16:58:20 -04001036bool GrD3DGpu::onSubmitToGpu(bool syncCpu) {
1037 if (syncCpu) {
1038 return this->submitDirectCommandList(SyncQueue::kForce);
1039 } else {
1040 return this->submitDirectCommandList(SyncQueue::kSkip);
1041 }
1042}