blob: 3cc41121dd805f53ca98dd499bb0f1ea2631a82e [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();
Jim Van Verth682a2f42020-05-13 16:54:09 -0400119 this->checkForFinishedCommandLists();
Jim Van Verthc632aa62020-04-17 16:58:20 -0400120 }
121 return true;
122 }
Greg Daniel83ed2132020-03-24 13:15:33 -0400123
124 new (fOutstandingCommandLists.push_back()) OutstandingCommandList(
125 std::move(fCurrentDirectCommandList), ++fCurrentFenceValue);
126
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400127 SkDEBUGCODE(HRESULT hr = ) fQueue->Signal(fFence.get(), fCurrentFenceValue);
Greg Daniel83ed2132020-03-24 13:15:33 -0400128 SkASSERT(SUCCEEDED(hr));
129
Jim Van Verthc632aa62020-04-17 16:58:20 -0400130 if (sync == SyncQueue::kForce) {
131 this->waitForQueueCompletion();
132 }
133
Greg Daniel83ed2132020-03-24 13:15:33 -0400134 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
135
136 // This should be done after we have a new command list in case the freeing of any resources
137 // held by a finished command list causes us send a new command to the gpu (like changing the
138 // resource state.
139 this->checkForFinishedCommandLists();
140
141 SkASSERT(fCurrentDirectCommandList);
Jim Van Verthc632aa62020-04-17 16:58:20 -0400142 return true;
Greg Daniel83ed2132020-03-24 13:15:33 -0400143}
144
145void GrD3DGpu::checkForFinishedCommandLists() {
146 uint64_t currentFenceValue = fFence->GetCompletedValue();
147
148 // Iterate over all the outstanding command lists to see if any have finished. The commands
149 // lists are in order from oldest to newest, so we start at the front to check if their fence
150 // value is less than the last signaled value. If so we pop it off and move onto the next.
151 // Repeat till we find a command list that has not finished yet (and all others afterwards are
152 // also guaranteed to not have finished).
153 SkDeque::F2BIter iter(fOutstandingCommandLists);
154 const OutstandingCommandList* curList = (const OutstandingCommandList*)iter.next();
155 while (curList && curList->fFenceValue <= currentFenceValue) {
156 curList = (const OutstandingCommandList*)iter.next();
157 OutstandingCommandList* front = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel7a5f1fa2020-03-24 14:50:19 -0400158 fResourceProvider.recycleDirectCommandList(std::move(front->fCommandList));
Greg Daniel83ed2132020-03-24 13:15:33 -0400159 // Since we used placement new we are responsible for calling the destructor manually.
160 front->~OutstandingCommandList();
161 fOutstandingCommandLists.pop_front();
162 }
163}
164
Jim Van Verthc632aa62020-04-17 16:58:20 -0400165void GrD3DGpu::waitForQueueCompletion() {
166 if (fFence->GetCompletedValue() < fCurrentFenceValue) {
167 HANDLE fenceEvent;
168 fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
169 SkASSERT(fenceEvent);
170 SkDEBUGCODE(HRESULT hr = ) fFence->SetEventOnCompletion(fCurrentFenceValue, fenceEvent);
171 SkASSERT(SUCCEEDED(hr));
172 WaitForSingleObject(fenceEvent, INFINITE);
173 CloseHandle(fenceEvent);
174 }
175}
176
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500177void GrD3DGpu::submit(GrOpsRenderPass* renderPass) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400178 SkASSERT(fCachedOpsRenderPass.get() == renderPass);
179
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500180 // TODO: actually submit something here
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400181 fCachedOpsRenderPass.reset();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500182}
183
184void GrD3DGpu::querySampleLocations(GrRenderTarget* rt, SkTArray<SkPoint>* sampleLocations) {
185 // TODO
186}
187
188sk_sp<GrTexture> GrD3DGpu::onCreateTexture(SkISize dimensions,
189 const GrBackendFormat& format,
190 GrRenderable renderable,
191 int renderTargetSampleCnt,
192 SkBudgeted budgeted,
193 GrProtected isProtected,
194 int mipLevelCount,
195 uint32_t levelClearMask) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400196 DXGI_FORMAT dxgiFormat;
197 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
198 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
199
200 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
201
202 if (renderable == GrRenderable::kYes) {
203 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
204 }
205
206 // This desc refers to the texture that will be read by the client. Thus even if msaa is
207 // requested, this describes the resolved texture. Therefore we always have samples set
208 // to 1.
209 SkASSERT(mipLevelCount > 0);
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400210 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400211 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
212 // TODO: will use 4MB alignment for MSAA textures and 64KB for everything else
213 // might want to manually set alignment to 4KB for smaller textures
214 resourceDesc.Alignment = 0;
215 resourceDesc.Width = dimensions.fWidth;
216 resourceDesc.Height = dimensions.fHeight;
217 resourceDesc.DepthOrArraySize = 1;
218 resourceDesc.MipLevels = mipLevelCount;
219 resourceDesc.Format = dxgiFormat;
220 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400221 // quality levels are only supported for tiled resources so ignore for now
222 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400223 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400224 resourceDesc.Flags = usageFlags;
225
226 GrMipMapsStatus mipMapsStatus =
227 mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
228
229 sk_sp<GrD3DTexture> tex;
230 if (renderable == GrRenderable::kYes) {
231 tex = GrD3DTextureRenderTarget::MakeNewTextureRenderTarget(
232 this, budgeted, dimensions, renderTargetSampleCnt, resourceDesc, isProtected,
233 mipMapsStatus);
234 } else {
235 tex = GrD3DTexture::MakeNewTexture(this, budgeted, dimensions, resourceDesc, isProtected,
236 mipMapsStatus);
237 }
238
239 if (!tex) {
240 return nullptr;
241 }
242
243 if (levelClearMask) {
244 // TODO
245 }
246 return std::move(tex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500247}
248
249sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
250 const GrBackendFormat& format,
251 SkBudgeted budgeted,
252 GrMipMapped mipMapped,
253 GrProtected isProtected,
254 const void* data, size_t dataSize) {
255 // TODO
256 return nullptr;
257}
258
Jim Van Verth9145f782020-04-28 12:01:12 -0400259static int get_surface_sample_cnt(GrSurface* surf) {
260 if (const GrRenderTarget* rt = surf->asRenderTarget()) {
261 return rt->numSamples();
262 }
263 return 0;
264}
265
266bool GrD3DGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
267 const SkIPoint& dstPoint) {
268
269 if (src->isProtected() && !dst->isProtected()) {
270 SkDebugf("Can't copy from protected memory to non-protected");
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400271 return false;
272 }
Jim Van Verth9145f782020-04-28 12:01:12 -0400273
274 int dstSampleCnt = get_surface_sample_cnt(dst);
275 int srcSampleCnt = get_surface_sample_cnt(src);
276
277 GrD3DTextureResource* dstTexResource;
278 GrD3DTextureResource* srcTexResource;
279 GrRenderTarget* dstRT = dst->asRenderTarget();
280 if (dstRT) {
281 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(dstRT);
282 dstTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
283 } else {
284 SkASSERT(dst->asTexture());
285 dstTexResource = static_cast<GrD3DTexture*>(dst->asTexture());
286 }
287 GrRenderTarget* srcRT = src->asRenderTarget();
288 if (srcRT) {
289 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(srcRT);
290 srcTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
291 } else {
292 SkASSERT(src->asTexture());
293 srcTexResource = static_cast<GrD3DTexture*>(src->asTexture());
294 }
295
296 DXGI_FORMAT dstFormat = dstTexResource->dxgiFormat();
297 DXGI_FORMAT srcFormat = srcTexResource->dxgiFormat();
298
299 if (this->d3dCaps().canCopyAsResolve(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
300 this->copySurfaceAsResolve(dst, src, srcRect, dstPoint);
301 return true;
302 }
303
304 if (this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
305 this->copySurfaceAsCopyTexture(dst, src, dstTexResource, srcTexResource, srcRect, dstPoint);
306 return true;
307 }
308
309 return false;
310}
311
312void GrD3DGpu::copySurfaceAsCopyTexture(GrSurface* dst, GrSurface* src,
313 GrD3DTextureResource* dstResource,
314 GrD3DTextureResource* srcResource,
315 const SkIRect& srcRect, const SkIPoint& dstPoint) {
316#ifdef SK_DEBUG
317 int dstSampleCnt = get_surface_sample_cnt(dst);
318 int srcSampleCnt = get_surface_sample_cnt(src);
319 DXGI_FORMAT dstFormat = dstResource->dxgiFormat();
320 DXGI_FORMAT srcFormat;
321 SkAssertResult(dst->backendFormat().asDxgiFormat(&srcFormat));
322 SkASSERT(this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt));
323#endif
324 if (src->isProtected() && !dst->isProtected()) {
325 SkDebugf("Can't copy from protected memory to non-protected");
326 return;
327 }
328
329 dstResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
330 srcResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
331
332 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
333 dstLocation.pResource = dstResource->d3dResource();
334 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
335 dstLocation.SubresourceIndex = 0;
336
337 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
338 srcLocation.pResource = srcResource->d3dResource();
339 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
340 srcLocation.SubresourceIndex = 0;
341
342 D3D12_BOX srcBox = {};
343 srcBox.left = srcRect.fLeft;
344 srcBox.top = srcRect.fTop;
345 srcBox.right = srcRect.fRight;
346 srcBox.bottom = srcRect.fBottom;
347 srcBox.front = 0;
348 srcBox.back = 1;
349 // TODO: use copyResource if copying full resource and sizes match
350 fCurrentDirectCommandList->copyTextureRegion(dstResource->resource(),
351 &dstLocation,
352 dstPoint.fX, dstPoint.fY,
353 srcResource->resource(),
354 &srcLocation,
355 &srcBox);
356
357 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
358 srcRect.width(), srcRect.height());
359 // The rect is already in device space so we pass in kTopLeft so no flip is done.
360 this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
361}
362
363void GrD3DGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
364 const SkIPoint& dstPoint) {
365 // TODO
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400366}
367
Jim Van Verthba7f2292020-04-21 08:56:47 -0400368bool GrD3DGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
369 GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
370 size_t rowBytes) {
371 SkASSERT(surface);
372
373 if (surfaceColorType != dstColorType) {
374 return false;
375 }
376
377 // Set up src location and box
Jim Van Verthc12aad92020-04-24 16:19:01 -0400378 GrD3DTextureResource* texResource = nullptr;
379 GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(surface->asRenderTarget());
380 if (rt) {
381 texResource = rt;
382 } else {
383 texResource = static_cast<GrD3DTexture*>(surface->asTexture());
384 }
385
386 if (!texResource) {
Jim Van Verthba7f2292020-04-21 08:56:47 -0400387 return false;
388 }
Jim Van Verthc12aad92020-04-24 16:19:01 -0400389
Jim Van Verthba7f2292020-04-21 08:56:47 -0400390 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
Jim Van Verthc12aad92020-04-24 16:19:01 -0400391 srcLocation.pResource = texResource->d3dResource();
Jim Van Verthba7f2292020-04-21 08:56:47 -0400392 SkASSERT(srcLocation.pResource);
393 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
394 srcLocation.SubresourceIndex = 0;
395
396 D3D12_BOX srcBox = {};
397 srcBox.left = left;
398 srcBox.top = top;
399 srcBox.right = left + width;
400 srcBox.bottom = top + height;
401 srcBox.front = 0;
402 srcBox.back = 1;
403
404 // Set up dst location and create transfer buffer
405 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
406 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400407 UINT64 transferTotalBytes;
408 const UINT64 baseOffset = 0;
409 D3D12_RESOURCE_DESC desc = srcLocation.pResource->GetDesc();
410 fDevice->GetCopyableFootprints(&desc, 0, 1, baseOffset, &dstLocation.PlacedFootprint,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400411 nullptr, nullptr, &transferTotalBytes);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400412 SkASSERT(transferTotalBytes);
Jim Van Verthfdd36852020-04-21 16:29:44 -0400413 size_t bpp = GrColorTypeBytesPerPixel(dstColorType);
Jim Van Verthc12aad92020-04-24 16:19:01 -0400414 if (this->d3dCaps().bytesPerPixel(texResource->dxgiFormat()) != bpp) {
Jim Van Verthfdd36852020-04-21 16:29:44 -0400415 return false;
416 }
417 size_t tightRowBytes = bpp * width;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400418
419 // TODO: implement some way of reusing buffers instead of making a new one every time.
420 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(transferTotalBytes,
421 GrGpuBufferType::kXferGpuToCpu,
422 kDynamic_GrAccessPattern);
423 GrD3DBuffer* d3dBuf = static_cast<GrD3DBuffer*>(transferBuffer.get());
424 dstLocation.pResource = d3dBuf->d3dResource();
425
426 // Need to change the resource state to COPY_SOURCE in order to download from it
Jim Van Verthc12aad92020-04-24 16:19:01 -0400427 texResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400428
429 fCurrentDirectCommandList->copyTextureRegion(d3dBuf->resource(), &dstLocation, 0, 0,
Jim Van Verthc12aad92020-04-24 16:19:01 -0400430 texResource->resource(), &srcLocation, &srcBox);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400431 this->submitDirectCommandList(SyncQueue::kForce);
432
433 const void* mappedMemory = transferBuffer->map();
434
435 SkRectMemcpy(buffer, rowBytes, mappedMemory, dstLocation.PlacedFootprint.Footprint.RowPitch,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400436 tightRowBytes, height);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400437
438 transferBuffer->unmap();
439
440 return true;
441}
442
443bool GrD3DGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
444 GrColorType surfaceColorType, GrColorType srcColorType,
445 const GrMipLevel texels[], int mipLevelCount,
446 bool prepForTexSampling) {
447 GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
448 if (!d3dTex) {
449 return false;
450 }
451
452 // Make sure we have at least the base level
453 if (!mipLevelCount || !texels[0].fPixels) {
454 return false;
455 }
456
457 SkASSERT(!GrDxgiFormatIsCompressed(d3dTex->dxgiFormat()));
458 bool success = false;
459
460 // Need to change the resource state to COPY_DEST in order to upload to it
461 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
462
463 SkASSERT(mipLevelCount <= d3dTex->texturePriv().maxMipMapLevel() + 1);
464 success = this->uploadToTexture(d3dTex, left, top, width, height, srcColorType, texels,
465 mipLevelCount);
466
467 if (prepForTexSampling) {
468 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
469 }
470
471 return success;
472}
473
474bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex, int left, int top, int width, int height,
475 GrColorType colorType, const GrMipLevel* texels, int mipLevelCount) {
476 SkASSERT(this->caps()->isFormatTexturable(tex->backendFormat()));
477 // The assumption is either that we have no mipmaps, or that our rect is the entire texture
478 SkASSERT(1 == mipLevelCount ||
479 (0 == left && 0 == top && width == tex->width() && height == tex->height()));
480
481 // We assume that if the texture has mip levels, we either upload to all the levels or just the
482 // first.
483 SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
484
485 if (width == 0 || height == 0) {
486 return false;
487 }
488
489 SkASSERT(this->d3dCaps().surfaceSupportsWritePixels(tex));
490 SkASSERT(this->d3dCaps().areColorTypeAndFormatCompatible(colorType, tex->backendFormat()));
491
492 ID3D12Resource* d3dResource = tex->d3dResource();
493 SkASSERT(d3dResource);
494 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
495 // Either upload only the first miplevel or all miplevels
496 SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
497
498 if (1 == mipLevelCount && !texels[0].fPixels) {
499 return true; // no data to upload
500 }
501
502 for (int i = 0; i < mipLevelCount; ++i) {
503 // We do not allow any gaps in the mip data
504 if (!texels[i].fPixels) {
505 return false;
506 }
507 }
508
509 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400510 UINT64 combinedBufferSize;
511 // We reset the width and height in the description to match our subrectangle size
512 // so we don't end up allocating more space than we need.
513 desc.Width = width;
514 desc.Height = height;
515 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
Jim Van Verthfdd36852020-04-21 16:29:44 -0400516 nullptr, nullptr, &combinedBufferSize);
517 size_t bpp = GrColorTypeBytesPerPixel(colorType);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400518 SkASSERT(combinedBufferSize);
519
520 // TODO: do this until we have slices of buttery buffers
521 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(combinedBufferSize,
522 GrGpuBufferType::kXferCpuToGpu,
523 kDynamic_GrAccessPattern);
524 if (!transferBuffer) {
525 return false;
526 }
527 char* bufferData = (char*)transferBuffer->map();
528
529 int currentWidth = width;
530 int currentHeight = height;
531 int layerHeight = tex->height();
532
533 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
534 if (texels[currentMipLevel].fPixels) {
535 SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
536
Jim Van Verthfdd36852020-04-21 16:29:44 -0400537 const size_t trimRowBytes = currentWidth * bpp;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400538 const size_t srcRowBytes = texels[currentMipLevel].fRowBytes;
539
540 char* dst = bufferData + placedFootprints[currentMipLevel].Offset;
541
542 // copy data into the buffer, skipping any trailing bytes
Jim Van Verthba7f2292020-04-21 08:56:47 -0400543 const char* src = (const char*)texels[currentMipLevel].fPixels;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400544 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
545 src, srcRowBytes, trimRowBytes, currentHeight);
546 }
547 currentWidth = std::max(1, currentWidth / 2);
548 currentHeight = std::max(1, currentHeight / 2);
549 layerHeight = currentHeight;
550 }
551
552 transferBuffer->unmap();
553
554 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get());
555 fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, tex, mipLevelCount,
556 placedFootprints.get(), left, top);
557
558 if (mipLevelCount < (int)desc.MipLevels) {
559 tex->texturePriv().markMipMapsDirty();
560 }
561
562 return true;
563}
564
Jim Van Verth280d4f72020-05-04 10:04:24 -0400565void GrD3DGpu::clear(const GrFixedClip& clip, const SkPMColor4f& color, GrRenderTarget* rt) {
566 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(rt);
567
568 d3dRT->setResourceState(this, D3D12_RESOURCE_STATE_RENDER_TARGET);
569
570 fCurrentDirectCommandList->clearRenderTargetView(d3dRT, color, clip);
571}
572
Jim Van Verth9145f782020-04-28 12:01:12 -0400573static bool check_resource_info(const GrD3DTextureResourceInfo& info) {
574 if (!info.fResource.get()) {
575 return false;
576 }
577 return true;
578}
579
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400580static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
581 if (!caps.isFormatTexturable(info.fFormat)) {
582 return false;
583 }
584 return true;
585}
586
587static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
588 int sampleCnt) {
589 if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
590 return false;
591 }
592 return true;
593}
594
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400595sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
596 GrWrapOwnership,
597 GrWrapCacheable wrapType,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400598 GrIOType ioType) {
599 GrD3DTextureResourceInfo textureInfo;
600 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
601 return nullptr;
602 }
603
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400604 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400605 return nullptr;
606 }
607
608 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
609 return nullptr;
610 }
611
612 // TODO: support protected context
613 if (tex.isProtected()) {
614 return nullptr;
615 }
616
617 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
618 SkASSERT(state);
619 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
620 std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500621}
622
623sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400624 GrWrapOwnership,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500625 GrWrapCacheable wrapType) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400626 GrD3DTextureResourceInfo textureInfo;
627 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
628 return nullptr;
629 }
630
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400631 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400632 return nullptr;
633 }
634
635 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
636 return nullptr;
637 }
638
639 // TODO: support protected context
640 if (tex.isProtected()) {
641 return nullptr;
642 }
643
644 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
645 SkASSERT(state);
646 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, kRead_GrIOType,
647 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500648}
649
650sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
651 int sampleCnt,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500652 GrWrapOwnership ownership,
653 GrWrapCacheable cacheable) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400654 GrD3DTextureResourceInfo textureInfo;
655 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
656 return nullptr;
657 }
658
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400659 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400660 return nullptr;
661 }
662
663 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
664 return nullptr;
665 }
666 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
667 return nullptr;
668 }
669
670 // TODO: support protected context
671 if (tex.isProtected()) {
672 return nullptr;
673 }
674
675 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
676
677 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
678 SkASSERT(state);
679
680 return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
681 sampleCnt, cacheable,
682 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500683}
684
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400685sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400686 // Currently the Direct3D backend does not support wrapping of msaa render targets directly. In
687 // general this is not an issue since swapchain images in D3D are never multisampled. Thus if
688 // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
689 // creating and owning the MSAA images.
690 if (rt.sampleCnt() > 1) {
691 return nullptr;
692 }
693
694 GrD3DTextureResourceInfo info;
695 if (!rt.getD3DTextureResourceInfo(&info)) {
696 return nullptr;
697 }
698
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400699 if (!check_resource_info(info)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400700 return nullptr;
701 }
702
703 if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
704 return nullptr;
705 }
706
707 // TODO: support protected context
708 if (rt.isProtected()) {
709 return nullptr;
710 }
711
712 sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
713
714 sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
715 this, rt.dimensions(), 1, info, std::move(state));
716
717 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
718 SkASSERT(!rt.stencilBits());
719 if (tgt) {
720 SkASSERT(tgt->canAttemptStencilAttachment());
721 }
722
723 return std::move(tgt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500724}
725
726sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400727 int sampleCnt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400728
729 GrD3DTextureResourceInfo textureInfo;
730 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
731 return nullptr;
732 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400733 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400734 return nullptr;
735 }
736
737 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
738 return nullptr;
739 }
740
741 // TODO: support protected context
742 if (tex.isProtected()) {
743 return nullptr;
744 }
745
746 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
747 if (!sampleCnt) {
748 return nullptr;
749 }
750
751 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
752 SkASSERT(state);
753
754 return GrD3DRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt,
755 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500756}
757
758sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
Jim Van Verthd6ad4802020-04-03 14:59:20 -0400759 GrAccessPattern accessPattern, const void* data) {
760 sk_sp<GrD3DBuffer> buffer = GrD3DBuffer::Make(this, sizeInBytes, type, accessPattern);
761 if (data && buffer) {
762 buffer->updateData(data, sizeInBytes);
763 }
764
765 return std::move(buffer);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500766}
767
768GrStencilAttachment* GrD3DGpu::createStencilAttachmentForRenderTarget(
769 const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
Jim Van Verth4f51f472020-04-13 11:02:21 -0400770 SkASSERT(numStencilSamples == rt->numSamples() || this->caps()->mixedSamplesSupport());
771 SkASSERT(width >= rt->width());
772 SkASSERT(height >= rt->height());
773
774 const GrD3DCaps::StencilFormat& sFmt = this->d3dCaps().preferredStencilFormat();
775
776 GrD3DStencilAttachment* stencil(GrD3DStencilAttachment::Make(this,
777 width,
778 height,
779 numStencilSamples,
780 sFmt));
781 fStats.incStencilAttachmentCreates();
782 return stencil;
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500783}
784
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400785bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
786 SkISize dimensions,
787 GrTexturable texturable,
788 GrRenderable renderable,
789 GrMipMapped mipMapped,
790 GrD3DTextureResourceInfo* info,
Greg Daniel16032b32020-05-06 15:31:10 -0400791 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400792 SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400793
794 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
795 return false;
796 }
797
798 if (texturable == GrTexturable::kYes && !this->d3dCaps().isFormatTexturable(dxgiFormat)) {
799 return false;
800 }
801
802 if (renderable == GrRenderable::kYes && !this->d3dCaps().isFormatRenderable(dxgiFormat, 1)) {
803 return false;
804 }
805
806 int numMipLevels = 1;
807 if (mipMapped == GrMipMapped::kYes) {
808 numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
809 }
810
811 // create the texture
812 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
813 if (renderable == GrRenderable::kYes) {
814 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
815 }
816
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400817 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400818 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
Greg Daniel16032b32020-05-06 15:31:10 -0400819 resourceDesc.Alignment = 0; // use default alignment
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400820 resourceDesc.Width = dimensions.fWidth;
821 resourceDesc.Height = dimensions.fHeight;
822 resourceDesc.DepthOrArraySize = 1;
823 resourceDesc.MipLevels = numMipLevels;
824 resourceDesc.Format = dxgiFormat;
825 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400826 // quality levels are only supported for tiled resources so ignore for now
827 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Greg Daniel16032b32020-05-06 15:31:10 -0400828 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400829 resourceDesc.Flags = usageFlags;
830
Jim Van Verth280d4f72020-05-04 10:04:24 -0400831 D3D12_CLEAR_VALUE* clearValuePtr = nullptr;
832 D3D12_CLEAR_VALUE clearValue = {};
833 if (renderable == GrRenderable::kYes) {
834 clearValue.Format = dxgiFormat;
835 // Assume transparent black
836 clearValue.Color[0] = 0;
837 clearValue.Color[1] = 0;
838 clearValue.Color[2] = 0;
839 clearValue.Color[3] = 0;
840 clearValuePtr = &clearValue;
841 }
842
Greg Daniel16032b32020-05-06 15:31:10 -0400843 D3D12_RESOURCE_STATES initialState = (renderable == GrRenderable::kYes)
844 ? D3D12_RESOURCE_STATE_RENDER_TARGET
845 : D3D12_RESOURCE_STATE_COPY_DEST;
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400846 if (!GrD3DTextureResource::InitTextureResourceInfo(this, resourceDesc, initialState,
Jim Van Verth280d4f72020-05-04 10:04:24 -0400847 isProtected, clearValuePtr, info)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400848 SkDebugf("Failed to init texture resource info\n");
849 return false;
850 }
851
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400852 return true;
853}
854
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500855GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400856 const GrBackendFormat& format,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400857 GrRenderable renderable,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400858 GrMipMapped mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400859 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400860 this->handleDirtyContext();
861
862 const GrD3DCaps& caps = this->d3dCaps();
863
864 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
865 return {};
866 }
867
868 DXGI_FORMAT dxgiFormat;
869 if (!format.asDxgiFormat(&dxgiFormat)) {
870 return {};
871 }
872
873 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
874 if (!caps.isFormatTexturable(dxgiFormat)) {
875 return {};
876 }
877
878 GrD3DTextureResourceInfo info;
879 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
880 renderable, mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400881 &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400882 return {};
883 }
884
885 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500886}
887
Greg Daniel16032b32020-05-06 15:31:10 -0400888bool GrD3DGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture,
889 sk_sp<GrRefCntedCallback> finishedCallback,
890 const BackendTextureData* data) {
891 // TODO: handle finishedCallback and data upload
892 return true;
893}
894
Greg Danielc1ad77c2020-05-06 11:40:03 -0400895GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(
896 SkISize dimensions, const GrBackendFormat& format, GrMipMapped mipMapped,
897 GrProtected isProtected, sk_sp<GrRefCntedCallback> finishedCallback,
898 const BackendTextureData* data) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400899 this->handleDirtyContext();
900
901 const GrD3DCaps& caps = this->d3dCaps();
902
903 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
904 return {};
905 }
906
907 DXGI_FORMAT dxgiFormat;
908 if (!format.asDxgiFormat(&dxgiFormat)) {
909 return {};
910 }
911
912 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
913 if (!caps.isFormatTexturable(dxgiFormat)) {
914 return {};
915 }
916
917 GrD3DTextureResourceInfo info;
918 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
919 GrRenderable::kNo, mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400920 &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400921 return {};
922 }
923
924 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500925}
926
927void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400928 SkASSERT(GrBackendApi::kDirect3D == tex.fBackend);
929 // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500930}
931
Robert Phillips979b2232020-02-20 10:47:29 -0500932bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
933 return false;
934}
935
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500936#if GR_TEST_UTILS
937bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400938 SkASSERT(GrBackendApi::kDirect3D == tex.backend());
939
940 GrD3DTextureResourceInfo info;
941 if (!tex.getD3DTextureResourceInfo(&info)) {
942 return false;
943 }
944 ID3D12Resource* textureResource = info.fResource.get();
945 if (!textureResource) {
946 return false;
947 }
948 return !(textureResource->GetDesc().Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500949}
950
951GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(int w, int h,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400952 GrColorType colorType) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400953 this->handleDirtyContext();
954
955 if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400956 return {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400957 }
958
959 DXGI_FORMAT dxgiFormat = this->d3dCaps().getFormatFromColorType(colorType);
960
961 GrD3DTextureResourceInfo info;
962 if (!this->createTextureResourceForBackendSurface(dxgiFormat, { w, h }, GrTexturable::kNo,
963 GrRenderable::kYes, GrMipMapped::kNo,
Greg Daniel16032b32020-05-06 15:31:10 -0400964 &info, GrProtected::kNo)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400965 return {};
966 }
967
968 return GrBackendRenderTarget(w, h, 1, info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500969}
970
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400971void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
972 SkASSERT(GrBackendApi::kDirect3D == rt.backend());
973
974 GrD3DTextureResourceInfo info;
975 if (rt.getD3DTextureResourceInfo(&info)) {
976 this->testingOnly_flushGpuAndSync();
977 // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
978 // is deleted.
979 }
980}
981
982void GrD3DGpu::testingOnly_flushGpuAndSync() {
Jim Van Verthc632aa62020-04-17 16:58:20 -0400983 SkAssertResult(this->submitDirectCommandList(SyncQueue::kForce));
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400984}
Jim Van Verthc632aa62020-04-17 16:58:20 -0400985
Jim Van Verth9b5e16c2020-04-20 10:45:52 -0400986void GrD3DGpu::testingOnly_startCapture() {
987 if (fGraphicsAnalysis) {
988 fGraphicsAnalysis->BeginCapture();
989 }
990}
991
992void GrD3DGpu::testingOnly_endCapture() {
993 if (fGraphicsAnalysis) {
994 fGraphicsAnalysis->EndCapture();
995 }
996}
997#endif
998
Jim Van Verthc632aa62020-04-17 16:58:20 -0400999///////////////////////////////////////////////////////////////////////////////
1000
Greg Daniela5a6b322020-04-23 12:52:27 -04001001void GrD3DGpu::addResourceBarriers(sk_sp<GrManagedResource> resource,
Jim Van Verthc632aa62020-04-17 16:58:20 -04001002 int numBarriers,
1003 D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
1004 SkASSERT(fCurrentDirectCommandList);
1005 SkASSERT(resource);
1006
Greg Daniela5a6b322020-04-23 12:52:27 -04001007 fCurrentDirectCommandList->resourceBarrier(std::move(resource), numBarriers, barriers);
Jim Van Verthc632aa62020-04-17 16:58:20 -04001008}
1009
Jim Van Verth682a2f42020-05-13 16:54:09 -04001010void GrD3DGpu::prepareSurfacesForBackendAccessAndExternalIO(
1011 GrSurfaceProxy* proxies[], int numProxies, SkSurface::BackendSurfaceAccess access,
1012 const GrPrepareForExternalIORequests& externalRequests) {
1013 SkASSERT(numProxies >= 0);
1014 SkASSERT(!numProxies || proxies);
1015
1016 // prepare proxies by transitioning to PRESENT renderState
1017 if (numProxies && access == SkSurface::BackendSurfaceAccess::kPresent) {
1018 GrD3DTextureResource* resource;
1019 for (int i = 0; i < numProxies; ++i) {
1020 SkASSERT(proxies[i]->isInstantiated());
1021 if (GrTexture* tex = proxies[i]->peekTexture()) {
1022 resource = static_cast<GrD3DTexture*>(tex);
1023 } else {
1024 GrRenderTarget* rt = proxies[i]->peekRenderTarget();
1025 SkASSERT(rt);
1026 resource = static_cast<GrD3DRenderTarget*>(rt);
1027 }
1028 resource->prepareForPresent(this);
1029 }
1030 }
1031}
1032
Jim Van Verthc632aa62020-04-17 16:58:20 -04001033bool GrD3DGpu::onSubmitToGpu(bool syncCpu) {
1034 if (syncCpu) {
1035 return this->submitDirectCommandList(SyncQueue::kForce);
1036 } else {
1037 return this->submitDirectCommandList(SyncQueue::kSkip);
1038 }
1039}